1 # Copyright 2015 ARM Limited 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # 15 from glob import iglob 16 import os 17 import signal 18 import shutil 19 import subprocess 20 import logging 21 from getpass import getpass 22 23 from devlib.exception import TargetError 24 from devlib.utils.misc import check_output 25 26 PACKAGE_BIN_DIRECTORY = os.path.join(os.path.dirname(__file__), 'bin') 27 28 def kill_children(pid, signal=signal.SIGKILL): 29 with open('/proc/{0}/task/{0}/children'.format(pid), 'r') as fd: 30 for cpid in map(int, fd.read().strip().split()): 31 kill_children(cpid, signal) 32 os.kill(cpid, signal) 33 34 class LocalConnection(object): 35 36 name = 'local' 37 38 def __init__(self, platform=None, keep_password=True, unrooted=False, 39 password=None, timeout=None): 40 self.logger = logging.getLogger('local_connection') 41 self.keep_password = keep_password 42 self.unrooted = unrooted 43 self.password = password 44 45 def push(self, source, dest, timeout=None, as_root=False): # pylint: disable=unused-argument 46 self.logger.debug('cp {} {}'.format(source, dest)) 47 shutil.copy(source, dest) 48 49 def pull(self, source, dest, timeout=None, as_root=False): # pylint: disable=unused-argument 50 self.logger.debug('cp {} {}'.format(source, dest)) 51 if ('*' in source or '?' in source) and os.path.isdir(dest): 52 # Pull all files matching a wildcard expression 53 for each_source in iglob(source): 54 shutil.copy(each_source, dest) 55 else: 56 shutil.copy(source, dest) 57 58 def execute(self, command, timeout=None, check_exit_code=True, 59 as_root=False, strip_colors=True): 60 self.logger.debug(command) 61 if as_root: 62 if self.unrooted: 63 raise TargetError('unrooted') 64 password = self._get_password() 65 command = 'echo \'{}\' | sudo -S '.format(password) + command 66 ignore = None if check_exit_code else 'all' 67 try: 68 return check_output(command, shell=True, timeout=timeout, ignore=ignore)[0] 69 except subprocess.CalledProcessError as e: 70 message = 'Got exit code {}\nfrom: {}\nOUTPUT: {}'.format( 71 e.returncode, command, e.output) 72 raise TargetError(message) 73 74 def background(self, command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, as_root=False): 75 if as_root: 76 if self.unrooted: 77 raise TargetError('unrooted') 78 password = self._get_password() 79 command = 'echo \'{}\' | sudo -S '.format(password) + command 80 return subprocess.Popen(command, stdout=stdout, stderr=stderr, shell=True) 81 82 def close(self): 83 pass 84 85 def cancel_running_command(self): 86 pass 87 88 def _get_password(self): 89 if self.password: 90 return self.password 91 password = getpass('sudo password:') 92 if self.keep_password: 93 self.password = password 94 return password 95