• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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