1#!/usr/bin/env python2 2# 3# Copyright 2010 Google Inc. All Rights Reserved. 4"""Script to enter the ChromeOS chroot with mounted sources. 5 6This script enters the chroot with mounted sources. 7""" 8 9from __future__ import print_function 10 11__author__ = 'asharif@google.com (Ahmad Sharif)' 12 13import argparse 14import getpass 15import os 16import pwd 17import sys 18 19from cros_utils import command_executer 20from cros_utils import logger 21from cros_utils import misc 22 23 24class MountPoint(object): 25 """Mount point class""" 26 27 def __init__(self, external_dir, mount_dir, owner, options=None): 28 self.external_dir = os.path.realpath(external_dir) 29 self.mount_dir = os.path.realpath(mount_dir) 30 self.owner = owner 31 self.options = options 32 33 def CreateAndOwnDir(self, dir_name): 34 retv = 0 35 if not os.path.exists(dir_name): 36 command = 'mkdir -p ' + dir_name 37 command += ' || sudo mkdir -p ' + dir_name 38 retv = command_executer.GetCommandExecuter().RunCommand(command) 39 if retv != 0: 40 return retv 41 pw = pwd.getpwnam(self.owner) 42 if os.stat(dir_name).st_uid != pw.pw_uid: 43 command = 'sudo chown -f ' + self.owner + ' ' + dir_name 44 retv = command_executer.GetCommandExecuter().RunCommand(command) 45 return retv 46 47 def DoMount(self): 48 ce = command_executer.GetCommandExecuter() 49 mount_signature = '%s on %s' % (self.external_dir, self.mount_dir) 50 command = 'mount' 51 retv, out, _ = ce.RunCommandWOutput(command) 52 if mount_signature not in out: 53 retv = self.CreateAndOwnDir(self.mount_dir) 54 logger.GetLogger().LogFatalIf(retv, 'Cannot create mount_dir!') 55 retv = self.CreateAndOwnDir(self.external_dir) 56 logger.GetLogger().LogFatalIf(retv, 'Cannot create external_dir!') 57 retv = self.MountDir() 58 logger.GetLogger().LogFatalIf(retv, 'Cannot mount!') 59 return retv 60 else: 61 return 0 62 63 def UnMount(self): 64 ce = command_executer.GetCommandExecuter() 65 return ce.RunCommand('sudo umount %s' % self.mount_dir) 66 67 def MountDir(self): 68 command = 'sudo mount --bind ' + self.external_dir + ' ' + self.mount_dir 69 if self.options == 'ro': 70 command += ' && sudo mount --bind -oremount,ro ' + self.mount_dir 71 retv = command_executer.GetCommandExecuter().RunCommand(command) 72 return retv 73 74 def __str__(self): 75 ret = '' 76 ret += self.external_dir + '\n' 77 ret += self.mount_dir + '\n' 78 if self.owner: 79 ret += self.owner + '\n' 80 if self.options: 81 ret += self.options + '\n' 82 return ret 83 84 85def Main(argv, return_output=False): 86 """The main function.""" 87 88 parser = argparse.ArgumentParser() 89 parser.add_argument( 90 '-c', 91 '--chromeos_root', 92 dest='chromeos_root', 93 default='../..', 94 help='ChromeOS root checkout directory.') 95 parser.add_argument( 96 '-t', 97 '--toolchain_root', 98 dest='toolchain_root', 99 help='Toolchain root directory.') 100 parser.add_argument( 101 '-o', '--output', dest='output', help='Toolchain output directory') 102 parser.add_argument( 103 '--sudo', 104 dest='sudo', 105 action='store_true', 106 default=False, 107 help='Run the command with sudo.') 108 parser.add_argument( 109 '-r', 110 '--third_party', 111 dest='third_party', 112 help='The third_party directory to mount.') 113 parser.add_argument( 114 '-m', 115 '--other_mounts', 116 dest='other_mounts', 117 help='Other mount points in the form: ' 118 'dir:mounted_dir:options') 119 parser.add_argument( 120 '-s', 121 '--mount-scripts-only', 122 dest='mount_scripts_only', 123 action='store_true', 124 default=False, 125 help='Mount only the scripts dir, and not the sources.') 126 parser.add_argument( 127 'passthrough_argv', 128 nargs='*', 129 help='Command to be executed inside the chroot.') 130 131 options = parser.parse_args(argv) 132 133 chromeos_root = options.chromeos_root 134 135 chromeos_root = os.path.expanduser(chromeos_root) 136 if options.toolchain_root: 137 options.toolchain_root = os.path.expanduser(options.toolchain_root) 138 139 chromeos_root = os.path.abspath(chromeos_root) 140 141 tc_dirs = [] 142 if options.toolchain_root is None or options.mount_scripts_only: 143 m = 'toolchain_root not specified. Will not mount toolchain dirs.' 144 logger.GetLogger().LogWarning(m) 145 else: 146 tc_dirs = [ 147 options.toolchain_root + '/google_vendor_src_branch/gcc', 148 options.toolchain_root + '/google_vendor_src_branch/binutils' 149 ] 150 151 for tc_dir in tc_dirs: 152 if not os.path.exists(tc_dir): 153 logger.GetLogger().LogError('toolchain path ' + tc_dir + 154 ' does not exist!') 155 parser.print_help() 156 sys.exit(1) 157 158 if not os.path.exists(chromeos_root): 159 logger.GetLogger().LogError('chromeos_root ' + options.chromeos_root + 160 ' does not exist!') 161 parser.print_help() 162 sys.exit(1) 163 164 if not os.path.exists(chromeos_root + '/src/scripts/build_packages'): 165 logger.GetLogger().LogError(options.chromeos_root + 166 '/src/scripts/build_packages' 167 ' not found!') 168 parser.print_help() 169 sys.exit(1) 170 171 version_dir = os.path.realpath(os.path.expanduser(os.path.dirname(__file__))) 172 173 mounted_tc_root = '/usr/local/toolchain_root' 174 full_mounted_tc_root = chromeos_root + '/chroot/' + mounted_tc_root 175 full_mounted_tc_root = os.path.abspath(full_mounted_tc_root) 176 177 mount_points = [] 178 for tc_dir in tc_dirs: 179 last_dir = misc.GetRoot(tc_dir)[1] 180 mount_point = MountPoint(tc_dir, full_mounted_tc_root + '/' + last_dir, 181 getpass.getuser(), 'ro') 182 mount_points.append(mount_point) 183 184 # Add the third_party mount point if it exists 185 if options.third_party: 186 third_party_dir = options.third_party 187 logger.GetLogger().LogFatalIf(not os.path.isdir(third_party_dir), 188 '--third_party option is not a valid dir.') 189 else: 190 third_party_dir = os.path.abspath( 191 '%s/../../../third_party' % os.path.dirname(__file__)) 192 193 if os.path.isdir(third_party_dir): 194 mount_point = MountPoint(third_party_dir, 195 ('%s/%s' % (full_mounted_tc_root, 196 os.path.basename(third_party_dir))), 197 getpass.getuser()) 198 mount_points.append(mount_point) 199 200 output = options.output 201 if output is None and options.toolchain_root: 202 # Mount the output directory at /usr/local/toolchain_root/output 203 output = options.toolchain_root + '/output' 204 205 if output: 206 mount_points.append( 207 MountPoint(output, full_mounted_tc_root + '/output', getpass.getuser())) 208 209 # Mount the other mount points 210 mount_points += CreateMountPointsFromString(options.other_mounts, 211 chromeos_root + '/chroot/') 212 213 last_dir = misc.GetRoot(version_dir)[1] 214 215 # Mount the version dir (v14) at /usr/local/toolchain_root/v14 216 mount_point = MountPoint(version_dir, full_mounted_tc_root + '/' + last_dir, 217 getpass.getuser()) 218 mount_points.append(mount_point) 219 220 for mount_point in mount_points: 221 retv = mount_point.DoMount() 222 if retv != 0: 223 return retv 224 225 # Finally, create the symlink to build-gcc. 226 command = 'sudo chown ' + getpass.getuser() + ' ' + full_mounted_tc_root 227 retv = command_executer.GetCommandExecuter().RunCommand(command) 228 229 try: 230 CreateSymlink(last_dir + '/build-gcc', full_mounted_tc_root + '/build-gcc') 231 CreateSymlink(last_dir + '/build-binutils', 232 full_mounted_tc_root + '/build-binutils') 233 except Exception as e: 234 logger.GetLogger().LogError(str(e)) 235 236 # Now call cros_sdk --enter with the rest of the arguments. 237 command = 'cd %s/src/scripts && cros_sdk --enter' % chromeos_root 238 239 if len(options.passthrough_argv) > 1: 240 inner_command = ' '.join(options.passthrough_argv[1:]) 241 inner_command = inner_command.strip() 242 if inner_command.startswith('-- '): 243 inner_command = inner_command[3:] 244 command_file = 'tc_enter_chroot.cmd' 245 command_file_path = chromeos_root + '/src/scripts/' + command_file 246 retv = command_executer.GetCommandExecuter().RunCommand( 247 'sudo rm -f ' + command_file_path) 248 if retv != 0: 249 return retv 250 f = open(command_file_path, 'w') 251 f.write(inner_command) 252 f.close() 253 logger.GetLogger().LogCmd(inner_command) 254 retv = command_executer.GetCommandExecuter().RunCommand( 255 'chmod +x ' + command_file_path) 256 if retv != 0: 257 return retv 258 259 if options.sudo: 260 command += ' sudo ./' + command_file 261 else: 262 command += ' ./' + command_file 263 retv = command_executer.GetCommandExecuter().RunCommandGeneric( 264 command, return_output) 265 return retv 266 else: 267 os.chdir('%s/src/scripts' % chromeos_root) 268 ce = command_executer.GetCommandExecuter() 269 _, out, _ = ce.RunCommandWOutput('which cros_sdk') 270 cros_sdk_binary = out.split()[0] 271 return os.execv(cros_sdk_binary, ['', '--enter']) 272 273 274def CreateMountPointsFromString(mount_strings, chroot_dir): 275 # String has options in the form dir:mount:options 276 mount_points = [] 277 if not mount_strings: 278 return mount_points 279 mount_list = mount_strings.split() 280 for mount_string in mount_list: 281 mount_values = mount_string.split(':') 282 external_dir = mount_values[0] 283 mount_dir = mount_values[1] 284 if len(mount_values) > 2: 285 options = mount_values[2] 286 else: 287 options = None 288 mount_point = MountPoint(external_dir, chroot_dir + '/' + mount_dir, 289 getpass.getuser(), options) 290 mount_points.append(mount_point) 291 return mount_points 292 293 294def CreateSymlink(target, link_name): 295 logger.GetLogger().LogFatalIf( 296 target.startswith('/'), "Can't create symlink to absolute path!") 297 real_from_file = misc.GetRoot(link_name)[0] + '/' + target 298 if os.path.realpath(real_from_file) != os.path.realpath(link_name): 299 if os.path.exists(link_name): 300 command = 'rm -rf ' + link_name 301 command_executer.GetCommandExecuter().RunCommand(command) 302 os.symlink(target, link_name) 303 304 305if __name__ == '__main__': 306 retval = Main(sys.argv) 307 sys.exit(retval) 308