15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python2.4
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2007, The Android Open Source Project
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License");
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# you may not use this file except in compliance with the License.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# You may obtain a copy of the License at
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     http://www.apache.org/licenses/LICENSE-2.0
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Unless required by applicable law or agreed to in writing, software
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distributed under the License is distributed on an "AS IS" BASIS,
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See the License for the specific language governing permissions and
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# limitations under the License.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# System imports
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import signal
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import tempfile
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import threading
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# local imports
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import errors
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logger
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_abort_on_error = False
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def SetAbortOnError(abort=True):
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Sets behavior of RunCommand to throw AbortError if command process returns
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  a negative error code"""
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  global _abort_on_error
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _abort_on_error = abort
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               stdin_input=None):
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Spawn and retry a subprocess to run the given shell command.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd: shell command to run
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timeout_time: time in seconds to wait for command to run before aborting.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retry_count: number of times to retry command
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_output: if True return output of command as string. Otherwise,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      direct output of command to stdout.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdin_input: data to feed to stdin
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output of command
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = None
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while True:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = RunOnce(cmd, timeout_time=timeout_time,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       return_output=return_output, stdin_input=stdin_input)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except errors.WaitForResponseTimedOutError:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if retry_count == 0:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retry_count -= 1
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logger.Log("No response for %s, retrying" % cmd)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Success
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Spawns a subprocess to run the given shell command.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd: shell command to run
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timeout_time: time in seconds to wait for command to run before aborting.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_output: if True return output of command as string. Otherwise,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      direct output of command to stdout.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdin_input: data to feed to stdin
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output of command
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errors.WaitForResponseTimedOutError if command did not complete within
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout_time seconds.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errors.AbortError is command returned error code and SetAbortOnError is on.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_time = time.time()
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  so = []
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  global _abort_on_error, error_occurred
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_occurred = False
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if return_output:
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output_dest = tempfile.TemporaryFile(bufsize=0)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else:
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # None means direct to stdout
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_dest = None
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if stdin_input:
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stdin_dest = subprocess.PIPE
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else:
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stdin_dest = None
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pipe = subprocess.Popen(
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cmd,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      executable='/bin/bash',
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stdin=stdin_dest,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stdout=output_dest,
101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      stderr=subprocess.STDOUT,
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      shell=True, close_fds=True,
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Run():
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global error_occurred
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pipe.communicate(input=stdin_input)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output = None
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if return_output:
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        output_dest.seek(0)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        output = output_dest.read()
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        output_dest.close()
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if output is not None and len(output) > 0:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        so.append(output)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except OSError, e:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logger.Log(e)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      so.append("ERROR")
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_occurred = True
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if pipe.returncode:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logger.SilentLog("Error: %s returned %d error code" %(cmd,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pipe.returncode))
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_occurred = True
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t = threading.Thread(target=Run)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t.start()
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  t.join(timeout_time)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if t.isAlive():
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    try:
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pipe.kill()
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except OSError:
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Can't kill a dead process.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pass
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    finally:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logger.SilentLog("about to raise a timeout for: %s" % cmd)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise errors.WaitForResponseTimedOutError
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output = "".join(so)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if _abort_on_error and error_occurred:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise errors.AbortError(msg=output)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "".join(so)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunHostCommand(binary, valgrind=False):
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Run a command on the host (opt using valgrind).
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Runs the host binary and returns the exit code.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  If successfull, the output (stdout and stderr) are discarded,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  but printed in case of error.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The command can be run under valgrind in which case all the
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output are always discarded.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    binary: full path of the file to be run.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    valgrind: If True the command will be run under valgrind.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The command exit code (int)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not valgrind:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subproc = subprocess.Popen(binary, stdout=subprocess.PIPE,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               stderr=subprocess.STDOUT)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subproc.wait()
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if subproc.returncode != 0:         # In case of error print the output
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print subproc.communicate()[0]
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return subproc.returncode
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Need the full path to valgrind to avoid other versions on the system.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                "--leak-check=yes", "-q", binary],
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Cannot rely on the retcode of valgrind. Instead look for an empty output.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    valgrind_out = subproc.communicate()[0].strip()
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if valgrind_out:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print valgrind_out
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def HasValgrind():
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Check that /usr/bin/valgrind exists.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  We look for the fullpath to avoid picking up 'alternative' valgrind
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  on the system.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    True if a system valgrind was found.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return os.path.exists("/usr/bin/valgrind")
193