| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # Copyright 2010 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Script to enter the ChromeOS chroot with mounted sources. |
| |
| This script enters the chroot with mounted sources. |
| """ |
| |
| from __future__ import print_function |
| |
| __author__ = '[email protected] (Ahmad Sharif)' |
| |
| import argparse |
| import getpass |
| import os |
| import pwd |
| import sys |
| |
| from cros_utils import command_executer |
| from cros_utils import logger |
| from cros_utils import misc |
| |
| |
| class MountPoint(object): |
| """Mount point class""" |
| |
| def __init__(self, external_dir, mount_dir, owner, options=None): |
| self.external_dir = os.path.realpath(external_dir) |
| self.mount_dir = os.path.realpath(mount_dir) |
| self.owner = owner |
| self.options = options |
| |
| def CreateAndOwnDir(self, dir_name): |
| retv = 0 |
| if not os.path.exists(dir_name): |
| command = 'mkdir -p ' + dir_name |
| command += ' || sudo mkdir -p ' + dir_name |
| retv = command_executer.GetCommandExecuter().RunCommand(command) |
| if retv != 0: |
| return retv |
| pw = pwd.getpwnam(self.owner) |
| if os.stat(dir_name).st_uid != pw.pw_uid: |
| command = 'sudo chown -f ' + self.owner + ' ' + dir_name |
| retv = command_executer.GetCommandExecuter().RunCommand(command) |
| return retv |
| |
| def DoMount(self): |
| ce = command_executer.GetCommandExecuter() |
| mount_signature = '%s on %s' % (self.external_dir, self.mount_dir) |
| command = 'mount' |
| retv, out, _ = ce.RunCommandWOutput(command) |
| if mount_signature not in out: |
| retv = self.CreateAndOwnDir(self.mount_dir) |
| logger.GetLogger().LogFatalIf(retv, 'Cannot create mount_dir!') |
| retv = self.CreateAndOwnDir(self.external_dir) |
| logger.GetLogger().LogFatalIf(retv, 'Cannot create external_dir!') |
| retv = self.MountDir() |
| logger.GetLogger().LogFatalIf(retv, 'Cannot mount!') |
| return retv |
| else: |
| return 0 |
| |
| def UnMount(self): |
| ce = command_executer.GetCommandExecuter() |
| return ce.RunCommand('sudo umount %s' % self.mount_dir) |
| |
| def MountDir(self): |
| command = 'sudo mount --bind ' + self.external_dir + ' ' + self.mount_dir |
| if self.options == 'ro': |
| command += ' && sudo mount --bind -oremount,ro ' + self.mount_dir |
| retv = command_executer.GetCommandExecuter().RunCommand(command) |
| return retv |
| |
| def __str__(self): |
| ret = '' |
| ret += self.external_dir + '\n' |
| ret += self.mount_dir + '\n' |
| if self.owner: |
| ret += self.owner + '\n' |
| if self.options: |
| ret += self.options + '\n' |
| return ret |
| |
| |
| def Main(argv, return_output=False): |
| """The main function.""" |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| '-c', |
| '--chromeos_root', |
| dest='chromeos_root', |
| default='../..', |
| help='ChromeOS root checkout directory.') |
| parser.add_argument( |
| '-t', |
| '--toolchain_root', |
| dest='toolchain_root', |
| help='Toolchain root directory.') |
| parser.add_argument( |
| '-o', '--output', dest='output', help='Toolchain output directory') |
| parser.add_argument( |
| '--sudo', |
| dest='sudo', |
| action='store_true', |
| default=False, |
| help='Run the command with sudo.') |
| parser.add_argument( |
| '-r', |
| '--third_party', |
| dest='third_party', |
| help='The third_party directory to mount.') |
| parser.add_argument( |
| '-m', |
| '--other_mounts', |
| dest='other_mounts', |
| help='Other mount points in the form: ' |
| 'dir:mounted_dir:options') |
| parser.add_argument( |
| '-s', |
| '--mount-scripts-only', |
| dest='mount_scripts_only', |
| action='store_true', |
| default=False, |
| help='Mount only the scripts dir, and not the sources.') |
| parser.add_argument( |
| 'passthrough_argv', |
| nargs='*', |
| help='Command to be executed inside the chroot.') |
| |
| options = parser.parse_args(argv) |
| |
| chromeos_root = options.chromeos_root |
| |
| chromeos_root = os.path.expanduser(chromeos_root) |
| if options.toolchain_root: |
| options.toolchain_root = os.path.expanduser(options.toolchain_root) |
| |
| chromeos_root = os.path.abspath(chromeos_root) |
| |
| tc_dirs = [] |
| if options.toolchain_root is None or options.mount_scripts_only: |
| m = 'toolchain_root not specified. Will not mount toolchain dirs.' |
| logger.GetLogger().LogWarning(m) |
| else: |
| tc_dirs = [ |
| options.toolchain_root + '/google_vendor_src_branch/gcc', |
| options.toolchain_root + '/google_vendor_src_branch/binutils' |
| ] |
| |
| for tc_dir in tc_dirs: |
| if not os.path.exists(tc_dir): |
| logger.GetLogger().LogError('toolchain path ' + tc_dir + |
| ' does not exist!') |
| parser.print_help() |
| sys.exit(1) |
| |
| if not os.path.exists(chromeos_root): |
| logger.GetLogger().LogError('chromeos_root ' + options.chromeos_root + |
| ' does not exist!') |
| parser.print_help() |
| sys.exit(1) |
| |
| if not os.path.exists(chromeos_root + '/src/scripts/build_packages'): |
| logger.GetLogger().LogError(options.chromeos_root + |
| '/src/scripts/build_packages' |
| ' not found!') |
| parser.print_help() |
| sys.exit(1) |
| |
| version_dir = os.path.realpath(os.path.expanduser(os.path.dirname(__file__))) |
| |
| mounted_tc_root = '/usr/local/toolchain_root' |
| full_mounted_tc_root = chromeos_root + '/chroot/' + mounted_tc_root |
| full_mounted_tc_root = os.path.abspath(full_mounted_tc_root) |
| |
| mount_points = [] |
| for tc_dir in tc_dirs: |
| last_dir = misc.GetRoot(tc_dir)[1] |
| mount_point = MountPoint(tc_dir, full_mounted_tc_root + '/' + last_dir, |
| getpass.getuser(), 'ro') |
| mount_points.append(mount_point) |
| |
| # Add the third_party mount point if it exists |
| if options.third_party: |
| third_party_dir = options.third_party |
| logger.GetLogger().LogFatalIf(not os.path.isdir(third_party_dir), |
| '--third_party option is not a valid dir.') |
| else: |
| third_party_dir = os.path.abspath( |
| '%s/../../../third_party' % os.path.dirname(__file__)) |
| |
| if os.path.isdir(third_party_dir): |
| mount_point = MountPoint( |
| third_party_dir, |
| ('%s/%s' % (full_mounted_tc_root, os.path.basename(third_party_dir))), |
| getpass.getuser()) |
| mount_points.append(mount_point) |
| |
| output = options.output |
| if output is None and options.toolchain_root: |
| # Mount the output directory at /usr/local/toolchain_root/output |
| output = options.toolchain_root + '/output' |
| |
| if output: |
| mount_points.append( |
| MountPoint(output, full_mounted_tc_root + '/output', getpass.getuser())) |
| |
| # Mount the other mount points |
| mount_points += CreateMountPointsFromString(options.other_mounts, |
| chromeos_root + '/chroot/') |
| |
| last_dir = misc.GetRoot(version_dir)[1] |
| |
| # Mount the version dir (v14) at /usr/local/toolchain_root/v14 |
| mount_point = MountPoint(version_dir, full_mounted_tc_root + '/' + last_dir, |
| getpass.getuser()) |
| mount_points.append(mount_point) |
| |
| for mount_point in mount_points: |
| retv = mount_point.DoMount() |
| if retv != 0: |
| return retv |
| |
| # Finally, create the symlink to build-gcc. |
| command = 'sudo chown ' + getpass.getuser() + ' ' + full_mounted_tc_root |
| retv = command_executer.GetCommandExecuter().RunCommand(command) |
| |
| try: |
| CreateSymlink(last_dir + '/build-gcc', full_mounted_tc_root + '/build-gcc') |
| CreateSymlink(last_dir + '/build-binutils', |
| full_mounted_tc_root + '/build-binutils') |
| except Exception as e: |
| logger.GetLogger().LogError(str(e)) |
| |
| # Now call cros_sdk --enter with the rest of the arguments. |
| command = 'cd %s/src/scripts && cros_sdk --enter' % chromeos_root |
| |
| if len(options.passthrough_argv) > 1: |
| inner_command = ' '.join(options.passthrough_argv[1:]) |
| inner_command = inner_command.strip() |
| if inner_command.startswith('-- '): |
| inner_command = inner_command[3:] |
| command_file = 'tc_enter_chroot.cmd' |
| command_file_path = chromeos_root + '/src/scripts/' + command_file |
| retv = command_executer.GetCommandExecuter().RunCommand('sudo rm -f ' + |
| command_file_path) |
| if retv != 0: |
| return retv |
| with open(command_file_path, 'w', encoding='utf-8') as f: |
| f.write(inner_command) |
| logger.GetLogger().LogCmd(inner_command) |
| retv = command_executer.GetCommandExecuter().RunCommand('chmod +x ' + |
| command_file_path) |
| if retv != 0: |
| return retv |
| |
| if options.sudo: |
| command += ' sudo ./' + command_file |
| else: |
| command += ' ./' + command_file |
| retv = command_executer.GetCommandExecuter().RunCommandGeneric( |
| command, return_output) |
| return retv |
| else: |
| os.chdir('%s/src/scripts' % chromeos_root) |
| ce = command_executer.GetCommandExecuter() |
| _, out, _ = ce.RunCommandWOutput('which cros_sdk') |
| cros_sdk_binary = out.split()[0] |
| return os.execv(cros_sdk_binary, ['', '--enter']) |
| |
| |
| def CreateMountPointsFromString(mount_strings, chroot_dir): |
| # String has options in the form dir:mount:options |
| mount_points = [] |
| if not mount_strings: |
| return mount_points |
| mount_list = mount_strings.split() |
| for mount_string in mount_list: |
| mount_values = mount_string.split(':') |
| external_dir = mount_values[0] |
| mount_dir = mount_values[1] |
| if len(mount_values) > 2: |
| options = mount_values[2] |
| else: |
| options = None |
| mount_point = MountPoint(external_dir, chroot_dir + '/' + mount_dir, |
| getpass.getuser(), options) |
| mount_points.append(mount_point) |
| return mount_points |
| |
| |
| def CreateSymlink(target, link_name): |
| logger.GetLogger().LogFatalIf( |
| target.startswith('/'), "Can't create symlink to absolute path!") |
| real_from_file = misc.GetRoot(link_name)[0] + '/' + target |
| if os.path.realpath(real_from_file) != os.path.realpath(link_name): |
| if os.path.exists(link_name): |
| command = 'rm -rf ' + link_name |
| command_executer.GetCommandExecuter().RunCommand(command) |
| os.symlink(target, link_name) |
| |
| |
| if __name__ == '__main__': |
| retval = Main(sys.argv) |
| sys.exit(retval) |