+
     GiD8  c                   s    ^ RI t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt	 RR lt
R tRR ltRR ltRR ltR tR tRR	 ltRR
 ltR tR tR tRR ltR# )i    Nc                s    . ROpW9  d   \        R\        V 4      ,           4      hVe   V R8X  d   \        R4      hV'       d   V R9   d   \        RV ,           4      hR# R# )zx
Raise an exception if the parameters passed to core() don't make sense
(all parameters are described in core() below).

backgroundzInvalid output value: Nz'Can't use check with output: backgroundz%Can't use output_return with output: )logstdoutinteractivetuir    pipe)r   r    )RuntimeErrorstr)outputoutput_returncheckZvals   &&& +/usr/lib/waydroid/tools/helpers/run_core.pysanity_checksr      sc    
 ID3c&kABB V|3DEE#88BVKLL 9}    c           
      s    T ;_uu_ 4        \        V P                  R 4       F7  p\        P                  ! WP	                  RR7      P                  4       4       K9  	  RRR4       R#   + '       g   i     R# ; i)r   replaceZerrorsN)Ziterreadlineloggingr   decoderstrip)r   ZlevelZline   && r   forward_streamr   &   sH    	,DKK{{){<CCEF - 
s   AA''A8	c                s   \         P                  ! V\         P                  \         P                  VR7      p\        P                  ! \
        VP                  \        P                  3RR7      P                  4        \        P                  ! \
        VP                  \        P                  3RR7      P                  4        \        P                  ! RP                  VP                  4      4       V# )zCRun a subprocess in background and redirect its output to the log. r   stderrcwdTZtargetargsdaemonz1New background process: pid={}, output=background)
subprocessPopenPIPE	threadingThreadr   r   r   DEBUGstartr   debugformatpid)r   cmdworking_dirprocr   r   r    r    ,   s    C

 +-DN$++w}}1MVZ[aacN$++w}}1MVZ[aacMMELLTXXVWKr   c                sb   \         P                  ! V\         P                  \         P                  VR7      p\        P                  ! \
        \        P                  \        P                  3RR7      P                  4        \        P                  ! RP                  VP                  4      4       V# )zBRun a subprocess in background and redirect its output to a pipe. r   Tr   z+New background process: pid={}, output=pipe)r   r   r   r    r!   r   r)   r   r   r"   r#   verboser%   r&   )r   r'   r(   retr   r   r   r   6   sm    


3zz*,CN$++w}}1MVZ[aacOOAHHQRJr   c                s    VP                   P                  4       p\        V4      '       d   \        P                  ! VP                  RR7      P                  4       4       V'       d*   \        P                   P                  P                  V4       V'       d   VP                  V4       K  V'       d   \        P                   P                  4        R# )a  
Read all available output from a subprocess and copy it to the log and
optionally stdout and a buffer variable. This is only meant to be called by
foreground_pipe() below.

:param process: subprocess.Popen instance
:param output_to_stdout: copy all output to waydroid's stdout
:param output_return: when set to True, output_return_buffer will be
                      extended
:param output_return_buffer: list of bytes that gets extended with the
                             current output in case output_return is True.
r   r   N)r   r   lenr   r$   r   r   sysZbufferZwriteappendZflush)r   processoutput_to_stdoutr	   Zoutput_return_bufferZouts   &&&&& r   	pipe_readr1   ?   s     nn%%'s88MM#**I*6==?@

!!'',$++C0 JJr   c                sJ   V'       d:   \         P                  P                  P                  V RR\	        V4      .RR7       M8\         P                  P                  P                  V RR\	        V4      .RR7       V F#  w  rEV\	        V4      8X  g   K  \        WW#4       K%  	  R# )z
Recursively kill a pid and its child processes

:param pid: process id that will be killed
:param ppids: list of process id and parent process id tuples (pid, ppid)
:param sudo: use sudo to kill the process
Zkillz-9F)r
   N)toolsZhelpersrunZrootr   Zuserkill_process_tree)r   r&   ppidssudoZ	child_pidZ
child_ppids   &&&&  r   r4   r4   ^   s     tfdCH%=#( 	 	* 	tfdCH%=#( 	 	* $)S!du; $)r   c                s   . ROp\         P                  ! VR\         P                  R7      p. pVP                  P	                  R4      P                  4       P                  R4      R,          pV FF  pVP                  4       p\        V4      ^8w  d   \        RV,           4      hVP                  V4       KH  	  \        WWR4       R# )	z
Kill a command process and recursively kill its child processes

:param pid: process id that will be killed
:param sudo: use sudo to kill the process
T)r
   r   utf-8Z
:i   NNzUnexpected ps output: N)Zpsz-ez-ozpid,ppid)r   r3   r   r   r   r   Zsplitr,   r   r.   r4   )	r   r&   r6   r'   r+   r5   Zproc_entriesZrowZitemss	   &&&      r   kill_commandr8   r   s     )C
..D
ACE::$$W-446<<TB2FL		u:?7#=>>U	  d-r   c                sV   \         P                  ! V\         P                  \         P                  VR7      pVP                  P                  4       p\        P                  ! V\        P                  4      p	\        P                  ! V\        P                  V	\        P                  ,          4       . p
\        P                  ! 4       pVP                  VP                  \        P                  4       V'       d   V P                  MRpVP!                  4       f   V'       d   \"        P$                  ! 4       MRpVP'                  V4       V'       d   \"        P$                  ! 4       pW,
          V P                  8  df   \(        P*                  ! R\-        V P                  4      ,           R,           4       \(        P*                  ! R4       \/        WP0                  V4       K  \3        WW4V
4       K  \3        WW4V
4       VP4                  RP7                  V
4      P9                  R4      3# )a#  
Run a subprocess in foreground with redirected output and optionally kill
it after being silent for too long.

:param cmd: command as list, e.g. ["echo", "string with spaces"]
:param working_dir: path in host system where the command should run
:param output_to_stdout: copy all output to waydroid's stdout
:param output_return: return the output of the whole program
:param output_timeout: kill the process when it doesn't print any output
                       after a certain time (configured with --timeout)
                       and raise a RuntimeError exception
:param sudo: use sudo to kill the process when it hits the timeout
:returns: (code, output)
          * code: return code of the program
          * output: ""
          * output: full program output string (output_return is True)
r   Nz%Process did not write any output for z seconds. Killing it.z6NOTE: The timeout can be increased with 'waydroid -t'.r   r7   )r   r   r   ZSTDOUTr   ZfilenofcntlZF_GETFLZF_SETFLosZ
O_NONBLOCK	selectorsZDefaultSelectorZregisterZ
EVENT_READtimeoutZpolltimeZperf_counterZselectr   infor   r8   r&   r1   Z
returncodeZjoinr   )r   r'   r(   r0   r	   output_timeoutr6   r/   ZhandleZflagsZoutput_bufferZselr<   Z
wait_startZwait_ends   &&&&&&&        r   foreground_piper@      s   * s:??&0&7&7[JG ^^""$FKK.E	KKur}}'<= M

#
#
%CLL!5!56,dll$G
,,.
 ,:T&&(


7
 ((*H$4D ./1HI J / 0T;;5 	$!1	! d-mL
  7 > >w GHHr   c                s|    \         P                  ! R4       \        P                  ! WR7      pVP	                  4       # )z
Run a subprocess in foreground without redirecting any of its output.

This is the only way text-based user interfaces (ncurses programs like
vim, nano or the kernel's menuconfig) work properly.
z9*** output passed to waydroid stdout, not to this log ***)r   )r   r$   r   r   wait)r'   r(   r/   r   r   foreground_tuirB      s1     MM  s4G<<>r   c                s    V'       dP   \         P                  ! R4       \         P                  ! RV P                  ,           4       \	        RV,           4      hR# )a]  
Check the return code of a command.

:param code: exit code to check
:param log_message: simplified and more readable form of the command, e.g.
                    "(native) % echo test" instead of the full command with
                    entering the chroot and more escaping
:raises RuntimeError: when the code indicates that the command failed
zINOTE: The failed command's output is above the ^^^ line in the log file: zCommand failed: NzF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^)r   r$   r>   r   r   )r   codelog_messages   &&&r   check_return_coderE      sF     h *,0HH5 	6-;<<	 r   c                 s    \         P                  ! RR.4      P                  4        \        P                  ! ^<\
        R7      p RV n        V P                  4        R# )z:
Run sudo -v and schedule a new timer to repeat the same.
r6   z-v)ZintervalZfunctionTN)r   r   rA   r    ZTimersudo_timer_iterater   r#   )Ztimers    r   rF   rF      s@    
 fd^$))+OOR2DEEEL	KKMr   c                s^    RV P                   9   d   R# RV P                   R&   \        4        R# )zW
Start a timer to call sudo -v periodically, so that the password is only
needed once.
Zsudo_timer_activeNT)ZcacherF   )r   s   &r   sudo_timer_startrG      s(     djj(&*DJJ"#r   c	           	     s   \        WEV4       V P                  '       d   V'       d   \        V 4       \        P                  ! V4       \        P
                  ! R\        V4      ,           4       VR8X  d   \        WV4      # VR8X  d   \        WV4      # Rp	VR8X  d   \        W#4      p
MCRpV P                  '       g
   VR9   d   RpVR	9   ;'       d    V'       * p\        WVVVVV4      w  rVRJd   \        W
V4       V'       d   V	# T
# )
a  
Run a command and create a log entry.

This is a low level function not meant to be used directly. Use one of the
following instead: tools.helpers.run.user(), tools.helpers.run.root(),
                   tools.chroot.user(), tools.chroot.root()

:param log_message: simplified and more readable form of the command, e.g.
                    "(native) % echo test" instead of the full command with
                    entering the chroot and more escaping
:param cmd: command as list, e.g. ["echo", "string with spaces"]
:param working_dir: path in host system where the command should run
:param output: where to write the output (stdout and stderr) of the
               process. We almost always write to the log file, which can
               be read with "waydroid log" (output values: "log",
               "stdout", "interactive", "background"), so it's easy to
               trace what waydroid does.

               The exceptions are "tui" (text-based user interface), where
               it does not make sense to write to the log file (think of
               ncurses UIs, such as "menuconfig") and "pipe" where the
               output is written to a pipe for manual asynchronous
               consumption by the caller.

               When the output is not set to "interactive", "tui",
               "background" or "pipe", we kill the process if it does not
               output anything for 5 minutes (time can be set with
               "waydroid --timeout").

               The table below shows all possible values along with
               their properties. "wait" indicates that we wait for the
               process to complete.

               output value  | timeout | out to log | out to stdout | wait
               -----------------------------------------------------------
               "log"         | x       | x          |               | x
               "stdout"      | x       | x          | x             | x
               "interactive" |         | x          | x             | x
               "tui"         |         |            | x             | x
               "background"  |         | x          |               |
               "pipe"        |         |            |               |

:param output_return: in addition to writing the program's output to the
                      destinations above in real time, write to a buffer
                      and return it as string when the command has
                      completed. This is not possible when output is
                      "background", "pipe" or "tui".
:param check: an exception will be raised when the command's return code
              is not 0. Set this to False to disable the check. This
              parameter can not be used when the output is "background" or
              "pipe".
:param sudo: use sudo to kill the process when it hits the timeout.
:returns: * program's return code (default)
          * subprocess.Popen instance (output is "background" or "pipe")
          * the program's entire output (output_return is True)
zrun: r    r   Z r   FT)r   r   )r   r   )r   Z
sudo_timerrG   r   r$   r*   r   r    r   rB   Zdetails_to_stdoutr@   rE   )r   rD   r'   r(   r   r	   r
   r6   Zdisable_timeoutZoutput_after_runrC   r0   r?   s   &&&&&&&&&    r   corerH      s   t &/4 MM+OOGc#h&' $[11 D{++ c/ !%%%&4M*M##44LL_9L#24k3C3@3A37	$9  E$k2  -6$6r   )r   FN)N)FFF)NFFTF)Nr   FNFF)r9   r   r;   r   r-   r    r=   r:   Ztools.helpers.runr2   r   r   r    r   r1   r4   r8   r@   rB   rE   rF   rG   rH   ) r   r   <module>rI      sm        
   	 
M(G><(.(=I@=$	
c7r   