
    hE                     `   d Z ddlZddlZddlZddlZddlZddlZddlZddl	Zddl
ZddlZddlmZ 	 ddlZdZej"                  j%                         rddlmZ nddlmZ 	  ej,                  ej.                  d         Zej4                  dk(  Zi Zej:                  j<                  j?                  d	d
dd      Z  e       d        Z! e       d        Z" e       d        Z#d Z$d Z%d Z&d Z'd Z(ddZ)d Z*d Z+d Z,d Z-d Z.d Z/d Z0e"Z1e#Z2e$Z3e%Z4e&Z5e'Z6e)Z7y# e$ r dZY w xY w# e$ r dZY w xY w)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                      t        j                         dk7  ryd} | D ]#  }t        j                  j	                  |      r# y y)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     X/var/www/betterdocs.net/sherlock_api/venv/lib/python3.12/site-packages/stem/util/proc.pyis_availabler   [   sE     __'! SJ WW^^D!     c                      t        j                          d}} t        dd|      }	 t        |j                         j	                         d         }t        |d|        |S #  t        d|z        }t        ||       |xY w)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C 
Is   8A A<c                      t        j                          d}} t        dd|      }	 t        |j                         d         dz  }t	        |d|        |S #  t        d|z        }t        ||       |xY w)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      s|     ))+'?i*_k9E.%%'*+d2F5zBM
H>Y
ZCC 
Is   -A A1c                     t        j                          d}}d| z  }| dk(  rd}n	 t        j                  |      }t        |||       |S # t        $ r t	        d|z        }t        ||       |w xY w)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      s     ))+ui* 3&-AX
CKK&c y-4	*  '-78c9c"is   A	 	&A/c                     t        j                          d}}d| z  }t        |d|      }	 t        |j                         d         }t	        |d|z  |       |S #  t        d|d|      }t        ||       |xY w)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C 
Is   -A !A9c           	      v   | dk(  ryt        j                          d}}d| z  }t        |d|      }	 t        |d   j                         d         dz  }t        |d	   j                         d         dz  }t	        |d
|z  |       ||fS #  t        d|ddj                  |            }t        ||       |xY w)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C 
Is   AB 0B8c           	         t         t        d      t        j                         ddj                  |      z  }}d| z  }t	        |t        |       |      }g }|j                  d      |j                  d      }}|dk7  rI|dk7  rD|j                  |d|        |j                  ||d	z   |        |||d	z   d j                         z  }t        |      d
k  r2t        |d   |d   |d         rt        d|z        }	t        ||	       |	g }
|D ]R  }|t        j                  k(  r,| dk(  r|
j                  d       .|
j                  |d	          C|t        j                  k(  rE| dk(  r|
j                  d       m|
j                  t        t        |d         t         z               |t        j                   k(  rE| dk(  r|
j                  d       |
j                  t        t        |d         t         z               |t        j"                  k(  s| dk(  rt%               c S t        |d         t         z  }|
j                  t        |t%               z                U t'        |||       t)        |
      S )aY  
  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      s2    
0
11))+|dii
6K'Ki* #)	3s8Y7) ) ~~c*INN3,?W)"_BYz	*+Yy1}W567Q;<(..00I^bYy}imYr]S
:YF
GCC 
I' @iDLL 	wy|$	dnn	$	ss52/+=>?	dnn	$	ss52/+=>?	doo	%	 ""
 Yr]+k9s<*;*==>?1@4 y)Z0	wr   c                    	 t        |       } | dk  rt        d| z        	 	 t	        t        j                  d| z              S # t        t        f$ r t        d| z        w xY w# t        $ r}t        d|z        d}~ww xY w)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 -A;;B c                    t        j                          g }}| r%d| z  }	 t        |       } | dk  rt        d| z        n
|rd|z  }nd}	 t
        st        d      | rt        |       n	t               }|rOt        j                  j                  j                  t        t        j                  |      j                              nd}d	D ]t  }|j!                  d
      r t"        j$                  j'                  |      s5|dd j)                  d
      }|j!                  d
      }		 t+        |d      5 }
|
j-                          |
D ]  }|j/                         dd \
  }}}}}}}}}}|r||vr(|r||k7  r0|dk(  r|dk7  r;|j1                  d      }t3        |d|       }t        ||dz   d d      }|j1                  d      }t3        |d|       }t        ||dz   d d      }|dk(  s|dk(  r|dk(  s|dk(  r|j5                  t        j                  j6                  j9                  ||||||	              	 ddd       w t=        |d|       |S # t        t        f$ r t        d| z        w xY w# 1 sw Y   <xY w# t        $ r}t        d|d|      d}~wt:        $ r}t        d|d|      d}~ww xY w# t        $ r}t?        ||        d}~ww xY w)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` &J		 	 	%bggnn^.L$++C0h'',gJ.$' 	l9



 ld>Bjjl3B>O;AueVQ1c1e%v-!3U"v**T"C!%+.FsQwx"-F**T"C!%+.FsQwx"-F"f0O&O1!KK		,,77PVX`bijk/l	l&JP 1:>Ko 	" =5;<<=,	l 	l6  I>3GHH JNCHIIJ
 
 
C 	
sm   I 	CJ9 !I:-DI.3I:;J9 I+.I7	3I::	J6JJ6 J11J66J9 9	KKKc                    t               }	 t        j                  d| z        }|D ]l  }d| d|}	 t        j
                  |      }|j                  d      r;|j                  t        j                  j                  j                  |dd              n |S # t        $ r}t	        d|z        d}~ww xY w# t        $ r:}t        j                  j                  |      sY d}~t	        d	|d
|      d}~ww xY w)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  ab"%r*Ga G$g			J	'

499&&002?@a" 
-) 
 C
;cA
BBC  aWW^^G$ RUW^_``as5   B A!B6	B3 B..B36	C9?C4#C44C9c           
         | t         vrEt        |       dk(  rjt        rt        j                  |       ddd   nt        j                  |       }t        j                  t
        j                  |      t         | <   t         |    S t        r`g }t        d      D ]>  }| d|z  d|dz   z   }|t        d      D cg c]  }|d|z  d|dz   z    c}ddd   z  }@ dj                  |      }n| }t        j                  j                  j                  t        j                  t
        j                  t        j                  |                  t         | <   t         |    S c c}w )a  
  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     sC     

4yA~0@  &tt,fFVFVW[F\g!++FNNGDl4* 
d	# 

 q 	LA!a%QU,(
E!HEqxAa1q5k2EddK
K(	L ((8$99//CCFDTDTU[UdUdflfvfvw~f  EA  Bl4	d	 Fs   4Ec                  H    	 | D ]  }t        |        y# t        $ r Y yw xY w)NTF)r"   rj   )valuevs     r   rZ   rZ     s4     Ah 	 s    	!!c                 $    t        | |f|      |   S )N)rE   )	file_pathline_prefixr)   s      r   r!   r!     s    	I		:;	GGr   c                    	 t        |      }t        |       i }}|D ]6  }|s n2|D ]+  }|j                  |      s|||<   |j                  |        6 8 |j	                          |rFt        |      dk(  r| d|d   d}t        |      | ddj                  |      d}t        |      |S # t        $ r}	t        ||	        d}	~	ww xY w)	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"wI & &??6" '&/

#
#F
+
		 OO		 A	%1:<Nq<QR CL 2;DIIFX<YZCLn	 
C 	
s   7B/ A4B/ /	C
8CC
c                 h    t        j                          |z
  }t        j                  d| ||fz         y)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*$'))1Yw4WWXr   c                 :    t        j                  d| d|       y)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 #D-,D-