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