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