blob: 93b3be2dec6c355da7d2d064f4a749ca39433891 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2010 The ChromiumOS Authors
# 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.
"""
__author__ = "asharif@google.com (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)