
    <iE                     p   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Jr   SSKrSr\R"                  R%                  5       (       a  SSKJr  OSSKJr   \R,                  " \R.                  S   5      r\R4                  S:H  r0 r\R:                  R<                  R?                  S	S
SS5      r \" 5       S 5       r!\" 5       S 5       r"\" 5       S 5       r#S r$S r%S r&S r'S r(SS jr)S r*S r+S r,S r-S r.S r/S r0\"r1\#r2\$r3\%r4\&r5\'r6\)r7g! \ a    Sr Nf = f! \ a    Sr Nf = f)a7  
Helper functions for querying process and system information from the /proc
contents. Fetching information this way provides huge performance benefits
over lookups via system utilities (ps, netstat, etc). For instance, resolving
connections this way cuts the runtime by around 90% verses the alternatives.
These functions may not work on all platforms (only Linux?).

The method for reading these files (and a little code) are borrowed from
`psutil <https://code.google.com/p/psutil/>`_, which was written by Jay Loden,
Dave Daeschler, Giampaolo Rodola' and is under the BSD license.

**These functions are not being vended to stem users. They may change in the
future, use them at your own risk.**

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

**Module Overview:**

::

  is_available - checks if proc utilities can be used on this system
  system_start_time - unix timestamp for when the system started
  physical_memory - memory available on this system
  cwd - provides the current working directory for a process
  uid - provides the user id a process is running under
  memory_usage - provides the memory usage of a process
  stats - queries statistics about a process
  file_descriptors_used - number of file descriptors used by a process
  connections - provides the connections made by a process

.. data:: Stat (enum)

  Types of data available via the :func:`~stem.util.proc.stats` function.

  ============== ===========
  Stat           Description
  ============== ===========
  **COMMAND**    command name under which the process is running
  **CPU_UTIME**  total user time spent on the process
  **CPU_STIME**  total system time spent on the process
  **START_TIME** when this process began, in unix time
  ============== ===========
    N)logTF)	lru_cache
SC_CLK_TCKlittle)COMMANDcommand)	CPU_UTIMEutime)	CPU_STIMEstime)
START_TIMEz
start timec                      [         R                  " 5       S:w  a  gSn U  H)  n[        R                  R	                  U5      (       a  M)    g   g)z
Checks if proc information is available on this platform.

:returns: **True** if proc contents exist on this platform, **False** otherwise
LinuxF)
/proc/stat/proc/meminfo/proc/net/tcp/proc/net/udpT)platformsystemospathexists)
proc_pathsr   s     H/home/james-whalen/.local/lib/python3.13/site-packages/stem/util/proc.pyis_availabler   [   sC     __'! SJWW^^D!!      c                      [         R                   " 5       Sp[        SSU5      n [        UR                  5       R	                  5       S   5      n[        USU 5        U$ !   [        SU-  5      n[        X5        Ue= f)z
Provides the unix time (seconds since epoch) when the system started.

:returns: **float** for the unix time of when the system started

:raises: **IOError** if it can't be determined
zsystem start timer   btime   z/proc/stat[btime]z.unable to parse the /proc/stat btime entry: %s)time	_get_linefloatstripsplit_log_runtimeIOError_log_failure)
start_time	parameter
btime_lineresultexcs        r   system_start_timer-   p   s|     ))+':iw	:*:##%++-a01F/<M
BZO
PC 
Is   8A A;c                      [         R                   " 5       Sp[        SSU5      n [        UR                  5       S   5      S-  n[	        USU 5        U$ !   [        SU-  5      n[        X5        Ue= f)z
Provides the total physical memory on the system in bytes.

:returns: **int** for the bytes of physical memory this system has

:raises: **IOError** if it can't be determined
zsystem physical memoryr   z	MemTotal:r      z/proc/meminfo[MemTotal]z4unable to parse the /proc/meminfo MemTotal entry: %sr    r!   intr$   r%   r&   r'   )r(   r)   mem_total_liner+   r,   s        r   physical_memoryr3      sx     ))+'?i_k9E.%%'*+d2F5zBM
H>Y
ZC 
Is   -A A0c                     [         R                   " 5       Sp!SU -  nU S:X  a  SnO [        R                  " U5      n[        X#U5        U$ ! [         a    [	        SU-  5      n[        X%5        Uef = f)z
Provides the current working directory for the given process.

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

:returns: **str** with the path of the working directory for the process

:raises: **IOError** if it can't be determined
cwdz/proc/%s/cwdr    zunable to read %s)r    r   readlinkOSErrorr&   r'   r%   )pidr(   r)   proc_cwd_linkr5   r,   s         r   r5   r5      sy     ))+ui 3&-AX
CKK&c y4	*  '-78c9"is   A
 
&A0c                     [         R                   " 5       Sp!SU -  n[        USU5      n [        UR                  5       S   5      n[	        USU-  U5        U$ !   [        SU< SU< 35      n[        X&5        Ue= f)z
Provides the user ID the given process is running under.

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

:returns: **int** with the user id for the owner of the process

:raises: **IOError** if it can't be determined
uid/proc/%s/statuszUid:r   z%s[Uid]unable to parse the z Uid entry: r0   )r9   r(   r)   status_pathuid_liner+   r,   s          r   r<   r<      s}     ))+ui!C'+{FI6(!!$%FI3Z@M
KR
SC 
Is   -A "A:c           	      x   U S:X  a  g[         R                   " 5       Sp!SU -  n[        USU5      n [        US   R                  5       S   5      S-  n[        US	   R                  5       S   5      S-  n[	        US
U-  U5        XV4$ !   [        SU< SSR                  U5      < 35      n[        X'5        Ue= f)a  
Provides the memory usage in bytes for the given process.

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

:returns: **tuple** of two ints with the memory usage of the process, of the
  form **(resident_size, virtual_size)**

:raises: **IOError** if it can't be determined
r   )r   r   zmemory usager=   )VmRSS:VmSize:rB   r   r/   rC   z%s[VmRSS|VmSize]r>   z VmRSS and VmSize entries: , )r    
_get_linesr1   r$   r%   r&   joinr'   )r9   r(   r)   r?   	mem_linesresidentSizevirtualSizer,   s           r   memory_usagerJ      s     	AX))+~i!C'+&;YG)	y*002156=Li	*002156=K.<jI&&
;X\XaXabkXlm
nC 
Is   AB 1B9c           	         [         c  [        S5      e[        R                  " 5       SSR                  U5      -  p2SU -  n[	        U[        U 5      U5      n/ nUR                  S5      UR                  S5      pUS:w  aH  US:w  aB  UR                  USU 5        UR                  XWS	-   U 5        XeUS	-   S R                  5       -  n[        U5      S
:  a6  [        US   US   US   5      (       a  [        SU-  5      n	[        X95        U	e/ n
U GHb  nU[        R                  :X  a/  U S:X  a  U
R                  S5        M1  U
R                  US	   5        MG  U[        R                  :X  aH  U S:X  a  U
R                  S5        Mt  U
R                  [        [        US   5      [         -  5      5        M  U[        R                   :X  aH  U S:X  a  U
R                  S5        M  U
R                  [        [        US   5      [         -  5      5        M  U[        R"                  :X  d  GM  U S:X  a  [%        5       s  $ [        US   5      [         -  nU
R                  [        U[%        5       -   5      5        GMe     ['        X4U5        [)        U
5      $ )aK  
Provides process specific information. See the :data:`~stem.util.proc.Stat`
enum for valid options.

:param int pid: process id of the process to be queried
:param Stat stat_types: information to be provided back

:returns: **tuple** with all of the requested statistics as strings

:raises: **IOError** if it can't be determined
NzUnable to look up SC_CLK_TCKz
process %srD   z/proc/%s/stat()r   ,            z&stat file had an unexpected format: %sr   sched0)CLOCK_TICKSr&   r    rF   r!   strfindappendr$   len	_is_floatr'   Statr   r	   r"   r   r   r-   r%   tuple)r9   
stat_typesr(   r)   	stat_path	stat_line	stat_comp	cmd_startcmd_endr,   results	stat_typep_start_times                r   statsrf      s"    
0
11))+|dii
6K'Ki #)	3s8Y7) ) ~~c*INN3,?W"_BYz	*+Y1}W567Q;<(..00I^bYy}imYr]SS
:YF
GC 
I'iDLL 	wy|$	dnn	$	ss52/+=>?	dnn	$	ss52/+=>?	doo	%	 ""
 Yr]+k9s<*;*==>?1 4 yZ0	wr   c                     [        U 5      n U S:  a  [        SU -  5      e  [	        [
        R                  " SU -  5      5      $ ! [        [        4 a    [        SU -  5      ef = f! [         a  n[        SU-  5      eSnAff = f)a  
Provides the number of file descriptors currently being used by a process.

.. versionadded:: 1.3.0

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

:returns: **int** of the number of file descriptors used

:raises: **IOError** if it can't be determined
r   "Process pids can't be negative: %sProcess pid was non-numeric: %sz/proc/%i/fdz3Unable to check number of file descriptors used: %sN)r1   r&   
ValueError	TypeErrorrY   r   listdir	Exception)r9   r,   s     r   file_descriptors_usedrn   8  s    ;
c(C
Qw83>?? 
Orzz-#-.//	 i	  ;
3c9
::;
 
 O
G#M
NNOs"   A !A' A$'
B1A??Bc                 L   [         R                   " 5       / p2U (       a&  SU -  n [        U 5      n U S:  a  [        SU -  5      eOU(       a  SU-  nOSn [
        (       d  [        S5      eU (       a  [        U 5      O	[        5       nU(       aP  [        R                  R                  R                  [        [        R                  " U5      R                  5      5      OSnS	 GH  nUR!                  S
5      (       a&  ["        R$                  R'                  U5      (       d  M@  USS R)                  S
5      nUR!                  S
5      n	 [+        US5       n
U
R-                  5         U
 GH  nUR/                  5       SS u
  pp    nnnnU(       a  UU;  a  M/  U(       a  UU:w  a  M>  US:X  a  US:w  a  ML  UR1                  S5      n[3        USU 5      n[        UUS-   S S5      nUR1                  S5      n[3        USU 5      n[        UUS-   S S5      nUS:X  d  US:X  a  M  US:X  d  US:X  a  M  UR5                  [        R                  R6                  R9                  UUUUX5      5        GM	     SSS5        GM     [=        USU5        U$ ! [        [        4 a    [        SU -  5      ef = f! , (       d  f       GM  = f! [         a  n[        SU< SU< 35      eSnAf[:         a  n[        SU< SU< 35      eSnAff = f! [         a  n[?        UU5        e SnAff = f)a  
Queries connections from the proc contents. This matches netstat, lsof, and
friends but is much faster. If no **pid** or **user** are provided this
provides all present connections.

:param int pid: pid to provide connections for
:param str user: username to look up connections for

:returns: **list** of :class:`~stem.util.connection.Connection` instances

:raises: **IOError** if it can't be determined
zconnections for pid %sr   rh   ri   zconnections for user %szall connectionszCThis requires python's pwd module, which is unavailable on Windows.N)r   z/proc/net/tcp6r   z/proc/net/udp66
   rbtcps   01   :r      z0.0.0.0z0000:0000:0000:0000:0000:0000zunable to read 'z': zunable to parse 'z/proc/net/[tcp|udp]) r    r1   r&   rj   rk   IS_PWD_AVAILABLE_inodes_for_socketssetstemutil	str_tools	_to_bytesrV   pwdgetpwnampw_uidendswithr   r   r   rstripopenreadliner$   rW   _unpack_addrrX   
connection
Connectionrm   r%   r'   )r9   userr(   connr)   inodesprocess_uidproc_file_pathprotocolis_ipv6	proc_fileline_l_dstr_dststatusr<   inodedivl_addrl_portr_addrr_portr,   s                           r   connectionsr   S  s    YY["d(3.I=Hc	q:S@AA 
 )D0I!I3
YZZ), %#%FSW$))%%//CLL4F4M4M0NO]aK`		 	 	%	%bggnn^.L.L$++C0h'',gJ.$'9



d>Bjjl3B>O;AeQ1c1e%v-!3U"v**T"C!%+.FsQwx"-F**T"C!%+.FsQwx"-F"f0O&O1!KK		,,77PVX`jk/   (' aP 1:>Ko 	" =5;<<=, ('6  I>3GHH JNCHIIJ
 
 
C 	
sy   J C2L KDJ/1K9L J,/
J?	9K<L ?K
LKL,K??LL 
L#LL#c                 &   [        5       n [        R                  " SU -  5      nU Hw  nSU < SU< 3n [        R
                  " U5      nUR                  S5      (       a=  UR                  [        R                  R                  R                  USS 5      5        Mw  My     U$ ! [         a  n[	        SU-  5      eSnAff = f! [         aB  n[        R                  R                  U5      (       d   SnAM  [	        S	U< S
U< 35      eSnAff = f)z
Provides inodes in use by a process for its sockets.

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

:returns: **set** with inodes for its sockets

:raises: **IOError** if it can't be determined
z/proc/%s/fdz'Unable to read our file descriptors: %sNz/proc/z/fd/zsocket:[   rN   z1unable to determine file descriptor destination (): )rx   r   rl   r8   r&   r7   
startswithaddry   rz   r{   r|   r   r   )r9   r   fd_contentsr,   fdfd_pathfd_names          r   rw   rw     s     5&C**]S01K b"%r*Ga G$g			J	'	'

499&&002?@ 
( " 
-) 
 C
;cA
BBC  aWW^^G$$ RUW^_``as5   B$ A'C$
C.B<<C
D$D8DDc           
         U [         ;  GaY  [        U 5      S:X  ar  [        (       a  [        R                  " U 5      SSS2   O[        R                  " U 5      n[
        R                  " [
        R                  U5      [         U '   [         U    $ [        (       ad  / n[        S5       HA  nU SU-  SUS-   -   nU[        S5       Vs/ s H  o4SU-  SUS-   -   PM     snSSS2   -  nMC     SR                  U5      nOU n[        R                  R                  R                  [
        R                  " [
        R                  [        R                  " U5      5      5      [         U '   [         U    $ s  snf )an  
Translates an address entry in the /proc/net/* contents to a human readable
form (`reference <http://linuxdevcenter.com/pub/a/linux/2000/11/16/LinuxAdmin.html>`_,
for instance:

::

  "0500000A" -> "10.0.0.5"
  "F804012A4A5190010000000002000000" -> "2a01:4f8:190:514a::2"

:param str addr: proc address entry to be decoded

:returns: **str** of the decoded address
r   NrN      r      r   )ENCODED_ADDRrY   IS_LITTLE_ENDIANbase64	b16decodesocket	inet_ntopAF_INETrangerF   ry   rz   r   expand_ipv6_addressAF_INET6)addrdecodedinvertedigroupingencodeds         r   r   r     sD     

4yA~0@0@  &tt,fFVFVW[F\g!++FNNGDl4* 
d	# 
	
 qA!a%QU,(
E!HEHqAa1q5k2HEddK
K(  ((8$99//CCFDTDTU[UdUdflfvfvw~f  EA  Bl4	d	 Fs   E.c                  N     U  H  n[        U5        M     g! [         a     gf = f)NTF)r"   rj   )valuevs     r   rZ   rZ     s/    Ah  	 s    
$$c                 "    [        X4U5      U   $ )N)rE   )	file_pathline_prefixr)   s      r   r!   r!     s    	I		:;	GGr   c                     [        U5      n[        U 5      0 pTU HC  nU(       d    O;U H1  nUR                  U5      (       d  M  XeU'   UR                  U5          MA     ME     UR	                  5         U(       aA  [        U5      S:X  a  U < SUS   < S3nOU < SSR                  U5      < S3n[        U5      eU$ ! [         a  n	[        X)5        e Sn	A	ff = f)	a  
Fetches lines with the given prefixes from a file. This only provides back
the first instance of each prefix.

:param str file_path: path of the file to read
:param tuple line_prefixes: string prefixes of the lines to return
:param str parameter: description of the proc attribute being fetch

:returns: mapping of prefixes to the matching line

:raises: **IOError** if unable to read the file or can't find all of the prefixes
r   z did not contain a r   z entryz did not contain rD   z entriesN)	listr   r   removecloserY   rF   r&   r'   )
r   line_prefixesr)   remaining_prefixesr   rc   r   prefixmsgr,   s
             r   rE   rE     s    
m,i"w&&??6"" &/

#
#F
+
	 '	  OO		 A	%1:<Nq<QR1:DIIFX<YZCLn	 
 	
s   >B< A7B< <
CCCc                 j    [         R                   " 5       U-
  n[        R                  " SXU4-  5        g)z
Logs a message indicating a successful proc query.

:param str parameter: description of the proc attribute being fetch
:param str proc_location: proc files we were querying
:param int start_time: unix time for when this query was started
z#proc call (%s): %s (runtime: %0.4f)N)r    r   debug)r)   proc_locationr(   runtimes       r   r%   r%   4  s+     IIK*$'))1Yw4WWXr   c                 @    [         R                  " SU < SU< 35        g)z
Logs a message indicating that the proc query failed.

:param str parameter: description of the proc attribute being fetch
:param Exception exc: exception that we're raising
zproc call failed (r   N)r   r   )r)   r,   s     r   r'   r'   A  s     ))9c:;r   )NN)8__doc__r   r   r   r   sysr    stem.prereqry   stem.util.connectionstem.util.enumstem.util.str_tools	stem.utilr   r}   rv   ImportErrorprereq_is_lru_cache_available	functoolsr   stem.util.lru_cachesysconfsysconf_namesrU   AttributeError	byteorderr   r   rz   enumEnumr[   r   r-   r3   r5   r<   rJ   rf   rn   r   rw   r   rZ   r!   rE   r%   r'   get_system_start_timeget_physical_memoryget_cwdget_uidget_memory_usage	get_statsget_connections r   r   <module>r      s  ,\  	   
       ;;&&((!+

2++L9:+ ==H, yy~~06  (  ,  ,82BAHO6R
j#L)XH)
X
Y< * % 

 	e    +s#   D %D* D'&D'*D54D5