blob: 40397f603b060bb5198b0c815fd7c0375fb9c224 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Mike Frysinger2de7f042012-07-10 04:45:03 -04002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Brian Harringb938c782012-02-29 15:14:38 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Manoj Gupta7fad04d2019-06-14 20:12:25 -07005
Mike Frysinger2f95cfc2015-06-04 04:00:26 -04006"""Manage SDK chroots.
7
8This script is used for manipulating local chroot environments; creating,
9deleting, downloading, etc. If given --enter (or no args), it defaults
10to an interactive bash shell within the chroot.
11
12If given args those are passed to the chroot environment, and executed.
13"""
Brian Harringb938c782012-02-29 15:14:38 -080014
Mike Frysinger383367e2014-09-16 15:06:17 -040015from __future__ import print_function
16
Mike Frysinger2f95cfc2015-06-04 04:00:26 -040017import argparse
Josh Triplett472a4182013-03-08 11:48:57 -080018import glob
Brian Harringb938c782012-02-29 15:14:38 -080019import os
Josh Triplett472a4182013-03-08 11:48:57 -080020import pwd
Benjamin Gordon2d7bf582017-07-12 10:11:26 -060021import random
Brian Norrisd37e2f72016-08-22 16:09:24 -070022import re
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -070023import resource
David James56e6c2c2012-10-24 23:54:41 -070024import sys
Mike Frysinger3dcacee2019-08-23 17:09:11 -040025
26from six.moves import urllib
Brian Harringb938c782012-02-29 15:14:38 -080027
Aviv Keshetb7519e12016-10-04 00:50:00 -070028from chromite.lib import constants
Brian Harringcfe762a2012-02-29 13:03:53 -080029from chromite.lib import cgroups
Brian Harringb6cf9142012-09-01 20:43:17 -070030from chromite.lib import commandline
Brian Harringb938c782012-02-29 15:14:38 -080031from chromite.lib import cros_build_lib
Ralph Nathan59900422015-03-24 10:41:17 -070032from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060033from chromite.lib import cros_sdk_lib
Brian Harringb938c782012-02-29 15:14:38 -080034from chromite.lib import locking
Josh Triplette759b232013-03-08 13:03:43 -080035from chromite.lib import namespaces
Brian Harringae0a5322012-09-15 01:46:51 -070036from chromite.lib import osutils
Yong Hong84ba9172018-02-07 01:37:42 +080037from chromite.lib import path_util
Mike Frysingere2d8f0d2014-11-01 13:09:26 -040038from chromite.lib import process_util
David Jamesc93e6a4d2014-01-13 11:37:36 -080039from chromite.lib import retry_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050040from chromite.lib import toolchain
Mike Frysingere652ba12019-09-08 00:57:43 -040041from chromite.utils import key_value_store
42
Brian Harringb938c782012-02-29 15:14:38 -080043
44cros_build_lib.STRICT_SUDO = True
45
Zdenek Behanaa52cea2012-05-30 01:31:11 +020046COMPRESSION_PREFERENCE = ('xz', 'bz2')
Zdenek Behanfd0efe42012-04-13 04:36:40 +020047
Brian Harringb938c782012-02-29 15:14:38 -080048# TODO(zbehan): Remove the dependency on these, reimplement them in python
Manoj Guptab12f7302019-06-03 16:40:14 -070049MAKE_CHROOT = [
50 os.path.join(constants.SOURCE_ROOT, 'src/scripts/sdk_lib/make_chroot.sh')
51]
52ENTER_CHROOT = [
53 os.path.join(constants.SOURCE_ROOT, 'src/scripts/sdk_lib/enter_chroot.sh')
54]
Brian Harringb938c782012-02-29 15:14:38 -080055
Josh Triplett472a4182013-03-08 11:48:57 -080056# Proxy simulator configuration.
57PROXY_HOST_IP = '192.168.240.1'
58PROXY_PORT = 8080
59PROXY_GUEST_IP = '192.168.240.2'
60PROXY_NETMASK = 30
61PROXY_VETH_PREFIX = 'veth'
62PROXY_CONNECT_PORTS = (80, 443, 9418)
63PROXY_APACHE_FALLBACK_USERS = ('www-data', 'apache', 'nobody')
64PROXY_APACHE_MPMS = ('event', 'worker', 'prefork')
65PROXY_APACHE_FALLBACK_PATH = ':'.join(
Manoj Guptab12f7302019-06-03 16:40:14 -070066 '/usr/lib/apache2/mpm-%s' % mpm for mpm in PROXY_APACHE_MPMS)
Josh Triplett472a4182013-03-08 11:48:57 -080067PROXY_APACHE_MODULE_GLOBS = ('/usr/lib*/apache2/modules', '/usr/lib*/apache2')
68
Josh Triplett9a495f62013-03-15 18:06:55 -070069# We need these tools to run. Very common tools (tar,..) are omitted.
Josh Triplette759b232013-03-08 13:03:43 -080070NEEDED_TOOLS = ('curl', 'xz')
Brian Harringb938c782012-02-29 15:14:38 -080071
Josh Triplett472a4182013-03-08 11:48:57 -080072# Tools needed for --proxy-sim only.
73PROXY_NEEDED_TOOLS = ('ip',)
Brian Harringb938c782012-02-29 15:14:38 -080074
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060075# Tools needed when use_image is true (the default).
76IMAGE_NEEDED_TOOLS = ('losetup', 'lvchange', 'lvcreate', 'lvs', 'mke2fs',
Benjamin Gordoncfa9c162017-08-03 13:49:29 -060077 'pvscan', 'thin_check', 'vgchange', 'vgcreate', 'vgs')
Benjamin Gordon386b9eb2017-07-20 09:21:33 -060078
Benjamin Gordone3d5bd12017-11-16 15:42:28 -070079# As space is used inside the chroot, the empty space in chroot.img is
80# allocated. Deleting files inside the chroot doesn't automatically return the
81# used space to the OS. Over time, this tends to make the sparse chroot.img
82# less sparse even if the chroot contents don't currently need much space. We
83# can recover most of this unused space with fstrim, but that takes too much
84# time to run it every time. Instead, check the used space against the image
85# size after mounting the chroot and only call fstrim if it looks like we could
86# recover at least this many GiB.
87MAX_UNUSED_IMAGE_GBS = 20
88
Mike Frysingercc838832014-05-24 13:10:30 -040089
Brian Harring1790ac42012-09-23 08:53:33 -070090def GetArchStageTarballs(version):
Brian Harringb938c782012-02-29 15:14:38 -080091 """Returns the URL for a given arch/version"""
Manoj Guptab12f7302019-06-03 16:40:14 -070092 extension = {'bz2': 'tbz2', 'xz': 'tar.xz'}
93 return [
94 toolchain.GetSdkURL(
95 suburl='cros-sdk-%s.%s' % (version, extension[compressor]))
96 for compressor in COMPRESSION_PREFERENCE
97 ]
Brian Harring1790ac42012-09-23 08:53:33 -070098
99
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700100def FetchRemoteTarballs(storage_dir, urls, desc, allow_none=False):
Mike Frysinger34db8692013-11-11 14:54:08 -0500101 """Fetches a tarball given by url, and place it in |storage_dir|.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200102
103 Args:
Mike Frysinger34db8692013-11-11 14:54:08 -0500104 storage_dir: Path where to save the tarball.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200105 urls: List of URLs to try to download. Download will stop on first success.
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700106 desc: A string describing what tarball we're downloading (for logging).
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700107 allow_none: Don't fail if none of the URLs worked.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200108
109 Returns:
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700110 Full path to the downloaded file, or None if |allow_none| and no URL worked.
111
112 Raises:
113 ValueError: If |allow_none| is False and none of the URLs worked.
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200114 """
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200115
Brian Harring1790ac42012-09-23 08:53:33 -0700116 # Note we track content length ourselves since certain versions of curl
117 # fail if asked to resume a complete file.
Brian Harring1790ac42012-09-23 08:53:33 -0700118 # https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3482927&group_id=976
Gilad Arnold6a8f0452015-06-04 11:25:18 -0700119 logging.notice('Downloading %s tarball...', desc)
Brian Norriscf8aef42016-09-27 10:43:39 -0700120 status_re = re.compile(r'^HTTP/[0-9]+(\.[0-9]+)? 200')
Mike Frysinger27e21b72018-07-12 14:20:21 -0400121 # pylint: disable=undefined-loop-variable
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200122 for url in urls:
Mike Frysinger3dcacee2019-08-23 17:09:11 -0400123 parsed = urllib.parse.urlparse(url)
Brian Harring1790ac42012-09-23 08:53:33 -0700124 tarball_name = os.path.basename(parsed.path)
125 if parsed.scheme in ('', 'file'):
126 if os.path.exists(parsed.path):
127 return parsed.path
128 continue
129 content_length = 0
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700130 logging.debug('Attempting download from %s', url)
Manoj Guptab12f7302019-06-03 16:40:14 -0700131 result = retry_util.RunCurl(['-I', url],
132 print_cmd=False,
133 debug_level=logging.NOTICE,
134 capture_output=True)
Brian Harring1790ac42012-09-23 08:53:33 -0700135 successful = False
136 for header in result.output.splitlines():
Brian Norrisd37e2f72016-08-22 16:09:24 -0700137 # We must walk the output to find the 200 code for use cases where
Brian Harring1790ac42012-09-23 08:53:33 -0700138 # a proxy is involved and may have pushed down the actual header.
Brian Norrisd37e2f72016-08-22 16:09:24 -0700139 if status_re.match(header):
Brian Harring1790ac42012-09-23 08:53:33 -0700140 successful = True
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500141 elif header.lower().startswith('content-length:'):
142 content_length = int(header.split(':', 1)[-1].strip())
Brian Harring1790ac42012-09-23 08:53:33 -0700143 if successful:
144 break
145 if successful:
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200146 break
147 else:
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700148 if allow_none:
149 return None
150 raise ValueError('No valid URLs found!')
Zdenek Behanfd0efe42012-04-13 04:36:40 +0200151
Brian Harringae0a5322012-09-15 01:46:51 -0700152 tarball_dest = os.path.join(storage_dir, tarball_name)
Brian Harring1790ac42012-09-23 08:53:33 -0700153 current_size = 0
154 if os.path.exists(tarball_dest):
155 current_size = os.path.getsize(tarball_dest)
156 if current_size > content_length:
David James56e6c2c2012-10-24 23:54:41 -0700157 osutils.SafeUnlink(tarball_dest)
Brian Harring1790ac42012-09-23 08:53:33 -0700158 current_size = 0
Zdenek Behanb2fa72e2012-03-16 04:49:30 +0100159
Brian Harring1790ac42012-09-23 08:53:33 -0700160 if current_size < content_length:
David Jamesc93e6a4d2014-01-13 11:37:36 -0800161 retry_util.RunCurl(
Hidehiko Abee55af7f2017-05-01 18:38:04 +0900162 ['--fail', '-L', '-y', '30', '-C', '-', '--output', tarball_dest, url],
Manoj Guptab12f7302019-06-03 16:40:14 -0700163 print_cmd=False,
164 debug_level=logging.NOTICE)
Brian Harringb938c782012-02-29 15:14:38 -0800165
Brian Harring1790ac42012-09-23 08:53:33 -0700166 # Cleanup old tarballs now since we've successfull fetched; only cleanup
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700167 # the tarballs for our prefix, or unknown ones. This gets a bit tricky
168 # because we might have partial overlap between known prefixes.
169 my_prefix = tarball_name.rsplit('-', 1)[0] + '-'
170 all_prefixes = ('stage3-amd64-', 'cros-sdk-', 'cros-sdk-overlay-')
171 ignored_prefixes = [prefix for prefix in all_prefixes if prefix != my_prefix]
Brian Harring1790ac42012-09-23 08:53:33 -0700172 for filename in os.listdir(storage_dir):
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700173 if (filename == tarball_name or
174 any([(filename.startswith(p) and
175 not (len(my_prefix) > len(p) and filename.startswith(my_prefix)))
176 for p in ignored_prefixes])):
Brian Harring1790ac42012-09-23 08:53:33 -0700177 continue
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700178 logging.info('Cleaning up old tarball: %s', filename)
David James56e6c2c2012-10-24 23:54:41 -0700179 osutils.SafeUnlink(os.path.join(storage_dir, filename))
Zdenek Behan9c644dd2012-04-05 06:24:02 +0200180
Brian Harringb938c782012-02-29 15:14:38 -0800181 return tarball_dest
182
183
Benjamin Gordon589873b2018-05-31 14:30:56 -0600184def CreateChroot(chroot_path, sdk_tarball, cache_dir, nousepkg=False):
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600185 """Creates a new chroot from a given SDK.
186
187 Args:
188 chroot_path: Path where the new chroot will be created.
189 sdk_tarball: Path to a downloaded Gentoo Stage3 or Chromium OS SDK tarball.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600190 cache_dir: Path to a directory that will be used for caching portage files,
191 etc.
192 nousepkg: If True, pass --nousepkg to cros_setup_toolchains inside the
193 chroot.
194 """
Brian Harringb938c782012-02-29 15:14:38 -0800195
Manoj Guptab12f7302019-06-03 16:40:14 -0700196 cmd = MAKE_CHROOT + [
197 '--stage3_path', sdk_tarball, '--chroot', chroot_path, '--cache_dir',
198 cache_dir
199 ]
Gilad Arnoldecc86fa2015-05-22 12:06:04 -0700200
Mike Frysinger2de7f042012-07-10 04:45:03 -0400201 if nousepkg:
202 cmd.append('--nousepkg')
Brian Harringb938c782012-02-29 15:14:38 -0800203
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700204 logging.notice('Creating chroot. This may take a few minutes...')
Brian Harringb938c782012-02-29 15:14:38 -0800205 try:
206 cros_build_lib.RunCommand(cmd, print_cmd=False)
207 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700208 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800209
210
211def DeleteChroot(chroot_path):
212 """Deletes an existing chroot"""
Manoj Guptab12f7302019-06-03 16:40:14 -0700213 cmd = MAKE_CHROOT + ['--chroot', chroot_path, '--delete']
Brian Harringb938c782012-02-29 15:14:38 -0800214 try:
Ralph Nathan7070e6a2015-04-02 10:16:43 -0700215 logging.notice('Deleting chroot.')
Brian Harringb938c782012-02-29 15:14:38 -0800216 cros_build_lib.RunCommand(cmd, print_cmd=False)
217 except cros_build_lib.RunCommandError:
Brian Harring98b54902012-03-23 04:05:42 -0700218 raise SystemExit('Running %r failed!' % cmd)
Brian Harringb938c782012-02-29 15:14:38 -0800219
220
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600221def CleanupChroot(chroot_path):
222 """Unmounts a chroot and cleans up any associated devices."""
Don Garrett36650112018-06-28 15:54:34 -0700223 cros_sdk_lib.CleanupChrootMount(chroot_path, delete=False)
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600224
225
Brian Harringae0a5322012-09-15 01:46:51 -0700226def EnterChroot(chroot_path, cache_dir, chrome_root, chrome_root_mount,
Mike Frysinger0b2d9ee2019-02-28 17:05:47 -0500227 goma_dir, goma_client_json, working_dir, additional_args):
Brian Harringb938c782012-02-29 15:14:38 -0800228 """Enters an existing SDK chroot"""
Mike Frysingere5456972013-06-13 00:07:23 -0400229 st = os.statvfs(os.path.join(chroot_path, 'usr', 'bin', 'sudo'))
230 # The os.ST_NOSUID constant wasn't added until python-3.2.
231 if st.f_flag & 0x2:
232 cros_build_lib.Die('chroot cannot be in a nosuid mount')
233
Brian Harringae0a5322012-09-15 01:46:51 -0700234 cmd = ENTER_CHROOT + ['--chroot', chroot_path, '--cache_dir', cache_dir]
Brian Harringb938c782012-02-29 15:14:38 -0800235 if chrome_root:
236 cmd.extend(['--chrome_root', chrome_root])
237 if chrome_root_mount:
238 cmd.extend(['--chrome_root_mount', chrome_root_mount])
Hidehiko Abeb5daf2f2017-03-02 17:57:43 +0900239 if goma_dir:
240 cmd.extend(['--goma_dir', goma_dir])
241 if goma_client_json:
242 cmd.extend(['--goma_client_json', goma_client_json])
Yong Hong84ba9172018-02-07 01:37:42 +0800243 if working_dir is not None:
244 cmd.extend(['--working_dir', working_dir])
Don Garrett230d1b22015-03-09 16:21:19 -0700245
Mike Frysinger53ffaae2019-08-27 16:30:27 -0400246 if additional_args:
Brian Harringb938c782012-02-29 15:14:38 -0800247 cmd.append('--')
248 cmd.extend(additional_args)
Brian Harring7199e7d2012-03-23 04:10:08 -0700249
Ting-Yuan Huangf56d9af2017-06-19 16:08:32 -0700250 # ThinLTO opens lots of files at the same time.
251 resource.setrlimit(resource.RLIMIT_NOFILE, (32768, 32768))
Manoj Guptab12f7302019-06-03 16:40:14 -0700252 ret = cros_build_lib.RunCommand(
253 cmd, print_cmd=False, error_code_ok=True, mute_output=False)
Brian Harring7199e7d2012-03-23 04:10:08 -0700254 # If we were in interactive mode, ignore the exit code; it'll be whatever
255 # they last ran w/in the chroot and won't matter to us one way or another.
256 # Note this does allow chroot entrance to fail and be ignored during
257 # interactive; this is however a rare case and the user will immediately
258 # see it (nor will they be checking the exit code manually).
259 if ret.returncode != 0 and additional_args:
Richard Barnette5c728a42015-03-18 11:50:21 -0700260 raise SystemExit(ret.returncode)
Brian Harringb938c782012-02-29 15:14:38 -0800261
262
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600263def _ImageFileForChroot(chroot):
264 """Find the image file that should be associated with |chroot|.
265
266 This function does not check if the image exists; it simply returns the
267 filename that would be used.
268
269 Args:
270 chroot: Path to the chroot.
271
272 Returns:
273 Path to an image file that would be associated with chroot.
274 """
275 return chroot.rstrip('/') + '.img'
276
277
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600278def CreateChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
279 """Create a snapshot for the specified chroot VG/LV.
280
281 Args:
282 snapshot_name: The name of the new snapshot.
283 chroot_vg: The name of the VG containing the origin LV.
284 chroot_lv: The name of the origin LV.
285
286 Returns:
287 True if the snapshot was created, or False if a snapshot with the same
288 name already exists.
289
290 Raises:
291 SystemExit: The lvcreate command failed.
292 """
293 if snapshot_name in ListChrootSnapshots(chroot_vg, chroot_lv):
Manoj Guptab12f7302019-06-03 16:40:14 -0700294 logging.error(
295 'Cannot create snapshot %s: A volume with that name already '
296 'exists.', snapshot_name)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600297 return False
298
Manoj Guptab12f7302019-06-03 16:40:14 -0700299 cmd = [
300 'lvcreate', '-s', '--name', snapshot_name,
301 '%s/%s' % (chroot_vg, chroot_lv)
302 ]
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600303 try:
304 logging.notice('Creating snapshot %s from %s in VG %s.', snapshot_name,
305 chroot_lv, chroot_vg)
306 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
307 return True
308 except cros_build_lib.RunCommandError:
309 raise SystemExit('Running %r failed!' % cmd)
310
311
312def DeleteChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
313 """Delete the named snapshot from the specified chroot VG.
314
315 If the requested snapshot is not found, nothing happens. The main chroot LV
316 and internal thinpool LV cannot be deleted with this function.
317
318 Args:
319 snapshot_name: The name of the snapshot to delete.
320 chroot_vg: The name of the VG containing the origin LV.
321 chroot_lv: The name of the origin LV.
322
323 Raises:
324 SystemExit: The lvremove command failed.
325 """
Benjamin Gordon74645232018-05-04 17:40:42 -0600326 if snapshot_name in (cros_sdk_lib.CHROOT_LV_NAME,
327 cros_sdk_lib.CHROOT_THINPOOL_NAME):
Manoj Guptab12f7302019-06-03 16:40:14 -0700328 logging.error(
329 'Cannot remove LV %s as a snapshot. Use cros_sdk --delete '
330 'if you want to remove the whole chroot.', snapshot_name)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600331 return
332
333 if snapshot_name not in ListChrootSnapshots(chroot_vg, chroot_lv):
334 return
335
336 cmd = ['lvremove', '-f', '%s/%s' % (chroot_vg, snapshot_name)]
337 try:
338 logging.notice('Deleting snapshot %s in VG %s.', snapshot_name, chroot_vg)
339 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
340 except cros_build_lib.RunCommandError:
341 raise SystemExit('Running %r failed!' % cmd)
342
343
344def RestoreChrootSnapshot(snapshot_name, chroot_vg, chroot_lv):
345 """Restore the chroot to an existing snapshot.
346
347 This is done by renaming the original |chroot_lv| LV to a temporary name,
348 renaming the snapshot named |snapshot_name| to |chroot_lv|, and deleting the
349 now unused LV. If an error occurs, attempts to rename the original snapshot
350 back to |chroot_lv| to leave the chroot unchanged.
351
352 The chroot must be unmounted before calling this function, and will be left
353 unmounted after this function returns.
354
355 Args:
356 snapshot_name: The name of the snapshot to restore. This snapshot will no
357 longer be accessible at its original name after this function finishes.
358 chroot_vg: The VG containing the chroot LV and snapshot LV.
359 chroot_lv: The name of the original chroot LV.
360
361 Returns:
362 True if the chroot was restored to the requested snapshot, or False if
363 the snapshot wasn't found or isn't valid.
364
365 Raises:
366 SystemExit: Any of the LVM commands failed.
367 """
368 valid_snapshots = ListChrootSnapshots(chroot_vg, chroot_lv)
Benjamin Gordon74645232018-05-04 17:40:42 -0600369 if (snapshot_name in (cros_sdk_lib.CHROOT_LV_NAME,
370 cros_sdk_lib.CHROOT_THINPOOL_NAME) or
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600371 snapshot_name not in valid_snapshots):
372 logging.error('Chroot cannot be restored to %s. Valid snapshots: %s',
373 snapshot_name, ', '.join(valid_snapshots))
374 return False
375
376 backup_chroot_name = 'chroot-bak-%d' % random.randint(0, 1000)
377 cmd = ['lvrename', chroot_vg, chroot_lv, backup_chroot_name]
378 try:
379 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
380 except cros_build_lib.RunCommandError:
381 raise SystemExit('Running %r failed!' % cmd)
382
383 cmd = ['lvrename', chroot_vg, snapshot_name, chroot_lv]
384 try:
385 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
386 except cros_build_lib.RunCommandError:
387 cmd = ['lvrename', chroot_vg, backup_chroot_name, chroot_lv]
388 try:
389 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
390 except cros_build_lib.RunCommandError:
391 raise SystemExit('Failed to rename %s to chroot and failed to restore '
392 '%s back to chroot. Failed command: %r' %
393 (snapshot_name, backup_chroot_name, cmd))
Manoj Guptab12f7302019-06-03 16:40:14 -0700394 raise SystemExit(
395 'Failed to rename %s to chroot. Original chroot LV has '
396 'been restored. Failed command: %r' % (snapshot_name, cmd))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600397
398 # Some versions of LVM set snapshots to be skipped at auto-activate time.
399 # Other versions don't have this flag at all. We run lvchange to try
400 # disabling auto-skip and activating the volume, but ignore errors. Versions
401 # that don't have the flag should be auto-activated.
402 chroot_lv_path = '%s/%s' % (chroot_vg, chroot_lv)
403 cmd = ['lvchange', '-kn', chroot_lv_path]
Manoj Guptab12f7302019-06-03 16:40:14 -0700404 cros_build_lib.RunCommand(
405 cmd, print_cmd=False, capture_output=True, error_code_ok=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600406
407 # Activate the LV in case the lvchange above was needed. Activating an LV
408 # that is already active shouldn't do anything, so this is safe to run even if
409 # the -kn wasn't needed.
410 cmd = ['lvchange', '-ay', chroot_lv_path]
411 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
412
413 cmd = ['lvremove', '-f', '%s/%s' % (chroot_vg, backup_chroot_name)]
414 try:
415 cros_build_lib.RunCommand(cmd, print_cmd=False, capture_output=True)
416 except cros_build_lib.RunCommandError:
417 raise SystemExit('Failed to remove backup LV %s/%s. Failed command: %r' %
418 (chroot_vg, backup_chroot_name, cmd))
419
420 return True
421
422
423def ListChrootSnapshots(chroot_vg, chroot_lv):
424 """Return all snapshots in |chroot_vg| regardless of origin volume.
425
426 Args:
427 chroot_vg: The name of the VG containing the chroot.
428 chroot_lv: The name of the chroot LV.
429
430 Returns:
431 A (possibly-empty) list of snapshot LVs found in |chroot_vg|.
432
433 Raises:
434 SystemExit: The lvs command failed.
435 """
436 if not chroot_vg or not chroot_lv:
437 return []
438
Manoj Guptab12f7302019-06-03 16:40:14 -0700439 cmd = [
440 'lvs', '-o', 'lv_name,pool_lv,lv_attr', '-O', 'lv_name', '--noheadings',
441 '--separator', '\t', chroot_vg
442 ]
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600443 try:
Manoj Guptab12f7302019-06-03 16:40:14 -0700444 result = cros_build_lib.RunCommand(
445 cmd, print_cmd=False, redirect_stdout=True)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600446 except cros_build_lib.RunCommandError:
447 raise SystemExit('Running %r failed!' % cmd)
448
449 # Once the thin origin volume has been deleted, there's no way to tell a
450 # snapshot apart from any other volume. Since this VG is created and managed
451 # by cros_sdk, we'll assume that all volumes that share the same thin pool are
452 # valid snapshots.
453 snapshots = []
454 snapshot_attrs = re.compile(r'^V.....t.{2,}') # Matches a thin volume.
455 for line in result.output.splitlines():
456 lv_name, pool_lv, lv_attr = line.lstrip().split('\t')
Manoj Guptab12f7302019-06-03 16:40:14 -0700457 if (lv_name == chroot_lv or lv_name == cros_sdk_lib.CHROOT_THINPOOL_NAME or
Benjamin Gordon74645232018-05-04 17:40:42 -0600458 pool_lv != cros_sdk_lib.CHROOT_THINPOOL_NAME or
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600459 not snapshot_attrs.match(lv_attr)):
460 continue
461 snapshots.append(lv_name)
462 return snapshots
463
464
David James56e6c2c2012-10-24 23:54:41 -0700465def _SudoCommand():
466 """Get the 'sudo' command, along with all needed environment variables."""
467
David James5a73b4d2013-03-07 10:23:40 -0800468 # Pass in the ENVIRONMENT_WHITELIST and ENV_PASSTHRU variables so that
469 # scripts in the chroot know what variables to pass through.
David James56e6c2c2012-10-24 23:54:41 -0700470 cmd = ['sudo']
David James5a73b4d2013-03-07 10:23:40 -0800471 for key in constants.CHROOT_ENVIRONMENT_WHITELIST + constants.ENV_PASSTHRU:
David James56e6c2c2012-10-24 23:54:41 -0700472 value = os.environ.get(key)
473 if value is not None:
474 cmd += ['%s=%s' % (key, value)]
475
476 # Pass in the path to the depot_tools so that users can access them from
477 # within the chroot.
Mike Frysinger08e75f12014-08-13 01:30:09 -0400478 cmd += ['DEPOT_TOOLS=%s' % constants.DEPOT_TOOLS_DIR]
Mike Frysinger749251e2014-01-29 05:04:27 -0500479
David James56e6c2c2012-10-24 23:54:41 -0700480 return cmd
481
482
Josh Triplett472a4182013-03-08 11:48:57 -0800483def _ReportMissing(missing):
484 """Report missing utilities, then exit.
485
486 Args:
487 missing: List of missing utilities, as returned by
488 osutils.FindMissingBinaries. If non-empty, will not return.
489 """
490
491 if missing:
492 raise SystemExit(
493 'The tool(s) %s were not found.\n'
494 'Please install the appropriate package in your host.\n'
495 'Example(ubuntu):\n'
Manoj Guptab12f7302019-06-03 16:40:14 -0700496 ' sudo apt-get install <packagename>' % ', '.join(missing))
Josh Triplett472a4182013-03-08 11:48:57 -0800497
498
499def _ProxySimSetup(options):
500 """Set up proxy simulator, and return only in the child environment.
501
502 TODO: Ideally, this should support multiple concurrent invocations of
503 cros_sdk --proxy-sim; currently, such invocations will conflict with each
504 other due to the veth device names and IP addresses. Either this code would
505 need to generate fresh, unused names for all of these before forking, or it
506 would need to support multiple concurrent cros_sdk invocations sharing one
507 proxy and allowing it to exit when unused (without counting on any local
508 service-management infrastructure on the host).
509 """
510
511 may_need_mpm = False
512 apache_bin = osutils.Which('apache2')
513 if apache_bin is None:
514 apache_bin = osutils.Which('apache2', PROXY_APACHE_FALLBACK_PATH)
515 if apache_bin is None:
516 _ReportMissing(('apache2',))
517 else:
518 may_need_mpm = True
519
520 # Module names and .so names included for ease of grepping.
521 apache_modules = [('proxy_module', 'mod_proxy.so'),
522 ('proxy_connect_module', 'mod_proxy_connect.so'),
523 ('proxy_http_module', 'mod_proxy_http.so'),
524 ('proxy_ftp_module', 'mod_proxy_ftp.so')]
525
526 # Find the apache module directory, and make sure it has the modules we need.
527 module_dirs = {}
528 for g in PROXY_APACHE_MODULE_GLOBS:
529 for mod, so in apache_modules:
530 for f in glob.glob(os.path.join(g, so)):
531 module_dirs.setdefault(os.path.dirname(f), []).append(so)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400532 for apache_module_path, modules_found in module_dirs.items():
Josh Triplett472a4182013-03-08 11:48:57 -0800533 if len(modules_found) == len(apache_modules):
534 break
535 else:
536 # Appease cros lint, which doesn't understand that this else block will not
537 # fall through to the subsequent code which relies on apache_module_path.
538 apache_module_path = None
539 raise SystemExit(
540 'Could not find apache module path containing all required modules: %s'
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500541 % ', '.join(so for mod, so in apache_modules))
Josh Triplett472a4182013-03-08 11:48:57 -0800542
543 def check_add_module(name):
544 so = 'mod_%s.so' % name
545 if os.access(os.path.join(apache_module_path, so), os.F_OK):
546 mod = '%s_module' % name
547 apache_modules.append((mod, so))
548 return True
549 return False
550
551 check_add_module('authz_core')
552 if may_need_mpm:
553 for mpm in PROXY_APACHE_MPMS:
554 if check_add_module('mpm_%s' % mpm):
555 break
556
557 veth_host = '%s-host' % PROXY_VETH_PREFIX
558 veth_guest = '%s-guest' % PROXY_VETH_PREFIX
559
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500560 # Set up locks to sync the net namespace setup. We need the child to create
561 # the net ns first, and then have the parent assign the guest end of the veth
562 # interface to the child's new network namespace & bring up the proxy. Only
563 # then can the child move forward and rely on the network being up.
564 ns_create_lock = locking.PipeLock()
565 ns_setup_lock = locking.PipeLock()
Josh Triplett472a4182013-03-08 11:48:57 -0800566
567 pid = os.fork()
568 if not pid:
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500569 # Create our new isolated net namespace.
Josh Triplett472a4182013-03-08 11:48:57 -0800570 namespaces.Unshare(namespaces.CLONE_NEWNET)
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500571
572 # Signal the parent the ns is ready to be configured.
573 ns_create_lock.Post()
574 del ns_create_lock
575
576 # Wait for the parent to finish setting up the ns/proxy.
577 ns_setup_lock.Wait()
578 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800579
580 # Set up child side of the network.
581 commands = (
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500582 ('ip', 'link', 'set', 'up', 'lo'),
Manoj Guptab12f7302019-06-03 16:40:14 -0700583 ('ip', 'address', 'add', '%s/%u' % (PROXY_GUEST_IP, PROXY_NETMASK),
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500584 'dev', veth_guest),
585 ('ip', 'link', 'set', veth_guest, 'up'),
Josh Triplett472a4182013-03-08 11:48:57 -0800586 )
587 try:
588 for cmd in commands:
589 cros_build_lib.RunCommand(cmd, print_cmd=False)
590 except cros_build_lib.RunCommandError:
591 raise SystemExit('Running %r failed!' % (cmd,))
592
593 proxy_url = 'http://%s:%u' % (PROXY_HOST_IP, PROXY_PORT)
594 for proto in ('http', 'https', 'ftp'):
595 os.environ[proto + '_proxy'] = proxy_url
596 for v in ('all_proxy', 'RSYNC_PROXY', 'no_proxy'):
597 os.environ.pop(v, None)
598 return
599
Josh Triplett472a4182013-03-08 11:48:57 -0800600 # Set up parent side of the network.
601 uid = int(os.environ.get('SUDO_UID', '0'))
602 gid = int(os.environ.get('SUDO_GID', '0'))
603 if uid == 0 or gid == 0:
604 for username in PROXY_APACHE_FALLBACK_USERS:
605 try:
606 pwnam = pwd.getpwnam(username)
607 uid, gid = pwnam.pw_uid, pwnam.pw_gid
608 break
609 except KeyError:
610 continue
611 if uid == 0 or gid == 0:
612 raise SystemExit('Could not find a non-root user to run Apache as')
613
614 chroot_parent, chroot_base = os.path.split(options.chroot)
615 pid_file = os.path.join(chroot_parent, '.%s-apache-proxy.pid' % chroot_base)
616 log_file = os.path.join(chroot_parent, '.%s-apache-proxy.log' % chroot_base)
617
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500618 # Wait for the child to create the net ns.
619 ns_create_lock.Wait()
620 del ns_create_lock
621
Josh Triplett472a4182013-03-08 11:48:57 -0800622 apache_directives = [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500623 'User #%u' % uid,
624 'Group #%u' % gid,
625 'PidFile %s' % pid_file,
626 'ErrorLog %s' % log_file,
627 'Listen %s:%u' % (PROXY_HOST_IP, PROXY_PORT),
628 'ServerName %s' % PROXY_HOST_IP,
629 'ProxyRequests On',
Mike Frysinger66ce4132019-07-17 22:52:52 -0400630 'AllowCONNECT %s' % ' '.join(str(x) for x in PROXY_CONNECT_PORTS),
Josh Triplett472a4182013-03-08 11:48:57 -0800631 ] + [
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500632 'LoadModule %s %s' % (mod, os.path.join(apache_module_path, so))
633 for (mod, so) in apache_modules
Josh Triplett472a4182013-03-08 11:48:57 -0800634 ]
635 commands = (
Manoj Guptab12f7302019-06-03 16:40:14 -0700636 ('ip', 'link', 'add', 'name', veth_host, 'type', 'veth', 'peer', 'name',
637 veth_guest),
638 ('ip', 'address', 'add', '%s/%u' % (PROXY_HOST_IP, PROXY_NETMASK), 'dev',
639 veth_host),
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500640 ('ip', 'link', 'set', veth_host, 'up'),
641 ([apache_bin, '-f', '/dev/null'] +
642 [arg for d in apache_directives for arg in ('-C', d)]),
643 ('ip', 'link', 'set', veth_guest, 'netns', str(pid)),
Josh Triplett472a4182013-03-08 11:48:57 -0800644 )
Manoj Guptab12f7302019-06-03 16:40:14 -0700645 cmd = None # Make cros lint happy.
Josh Triplett472a4182013-03-08 11:48:57 -0800646 try:
647 for cmd in commands:
648 cros_build_lib.RunCommand(cmd, print_cmd=False)
649 except cros_build_lib.RunCommandError:
650 # Clean up existing interfaces, if any.
651 cmd_cleanup = ('ip', 'link', 'del', veth_host)
652 try:
653 cros_build_lib.RunCommand(cmd_cleanup, print_cmd=False)
654 except cros_build_lib.RunCommandError:
Ralph Nathan59900422015-03-24 10:41:17 -0700655 logging.error('running %r failed', cmd_cleanup)
Josh Triplett472a4182013-03-08 11:48:57 -0800656 raise SystemExit('Running %r failed!' % (cmd,))
Mike Frysinger77bf4af2016-02-26 17:13:15 -0500657
658 # Signal the child that the net ns/proxy is fully configured now.
659 ns_setup_lock.Post()
660 del ns_setup_lock
Josh Triplett472a4182013-03-08 11:48:57 -0800661
Mike Frysingere2d8f0d2014-11-01 13:09:26 -0400662 process_util.ExitAsStatus(os.waitpid(pid, 0)[1])
Josh Triplett472a4182013-03-08 11:48:57 -0800663
664
Mike Frysingera78a56e2012-11-20 06:02:30 -0500665def _ReExecuteIfNeeded(argv):
David James56e6c2c2012-10-24 23:54:41 -0700666 """Re-execute cros_sdk as root.
667
668 Also unshare the mount namespace so as to ensure that processes outside
669 the chroot can't mess with our mounts.
670 """
671 if os.geteuid() != 0:
Mike Frysingera78a56e2012-11-20 06:02:30 -0500672 cmd = _SudoCommand() + ['--'] + argv
673 os.execvp(cmd[0], cmd)
Mike Frysingera78a56e2012-11-20 06:02:30 -0500674 else:
Mike Frysinger80dfce92014-04-21 10:58:53 -0400675 # We must set up the cgroups mounts before we enter our own namespace.
676 # This way it is a shared resource in the root mount namespace.
Josh Triplette759b232013-03-08 13:03:43 -0800677 cgroups.Cgroup.InitSystem()
David James56e6c2c2012-10-24 23:54:41 -0700678
679
Mike Frysinger34db8692013-11-11 14:54:08 -0500680def _CreateParser(sdk_latest_version, bootstrap_latest_version):
681 """Generate and return the parser with all the options."""
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400682 usage = ('usage: %(prog)s [options] '
683 '[VAR1=val1 ... VAR2=val2] [--] [command [args]]')
Manoj Guptab12f7302019-06-03 16:40:14 -0700684 parser = commandline.ArgumentParser(
685 usage=usage, description=__doc__, caching=True)
Brian Harring218e13c2012-10-10 16:21:26 -0700686
Mike Frysinger34db8692013-11-11 14:54:08 -0500687 # Global options.
Mike Frysinger648ba2d2013-01-08 14:19:34 -0500688 default_chroot = os.path.join(constants.SOURCE_ROOT,
689 constants.DEFAULT_CHROOT_DIR)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400690 parser.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700691 '--chroot',
692 dest='chroot',
693 default=default_chroot,
694 type='path',
Brian Harring218e13c2012-10-10 16:21:26 -0700695 help=('SDK chroot dir name [%s]' % constants.DEFAULT_CHROOT_DIR))
Manoj Guptab12f7302019-06-03 16:40:14 -0700696 parser.add_argument(
697 '--nouse-image',
698 dest='use_image',
699 action='store_false',
700 default=True,
701 help='Do not mount the chroot on a loopback image; '
702 'instead, create it directly in a directory.')
Brian Harringb938c782012-02-29 15:14:38 -0800703
Manoj Guptab12f7302019-06-03 16:40:14 -0700704 parser.add_argument(
Alex Klein5e4b1bc2019-07-02 12:27:06 -0600705 '--chrome-root',
Manoj Guptab12f7302019-06-03 16:40:14 -0700706 '--chrome_root',
707 type='path',
708 help='Mount this chrome root into the SDK chroot')
709 parser.add_argument(
710 '--chrome_root_mount',
711 type='path',
712 help='Mount chrome into this path inside SDK chroot')
713 parser.add_argument(
714 '--nousepkg',
715 action='store_true',
716 default=False,
717 help='Do not use binary packages when creating a chroot.')
718 parser.add_argument(
719 '-u',
720 '--url',
721 dest='sdk_url',
722 help='Use sdk tarball located at this url. Use file:// '
723 'for local files.')
724 parser.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700725 '--sdk-version',
726 help=('Use this sdk version. For prebuilt, current is %r'
727 ', for bootstrapping it is %r.' % (sdk_latest_version,
728 bootstrap_latest_version)))
729 parser.add_argument(
730 '--goma_dir',
731 type='path',
732 help='Goma installed directory to mount into the chroot.')
733 parser.add_argument(
734 '--goma_client_json',
735 type='path',
736 help='Service account json file to use goma on bot. '
737 'Mounted into the chroot.')
Yong Hong84ba9172018-02-07 01:37:42 +0800738
739 # Use type=str instead of type='path' to prevent the given path from being
740 # transfered to absolute path automatically.
Manoj Guptab12f7302019-06-03 16:40:14 -0700741 parser.add_argument(
742 '--working-dir',
743 type=str,
744 help='Run the command in specific working directory in '
745 'chroot. If the given directory is a relative '
746 'path, this program will transfer the path to '
747 'the corresponding one inside chroot.')
Yong Hong84ba9172018-02-07 01:37:42 +0800748
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400749 parser.add_argument('commands', nargs=argparse.REMAINDER)
Mike Frysinger34db8692013-11-11 14:54:08 -0500750
751 # Commands.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400752 group = parser.add_argument_group('Commands')
753 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700754 '--enter',
755 action='store_true',
756 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500757 help='Enter the SDK chroot. Implies --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400758 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700759 '--create',
760 action='store_true',
761 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500762 help='Create the chroot only if it does not already exist. '
763 'Implies --download.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400764 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700765 '--bootstrap',
766 action='store_true',
767 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500768 help='Build everything from scratch, including the sdk. '
769 'Use this only if you need to validate a change '
770 'that affects SDK creation itself (toolchain and '
771 'build are typically the only folk who need this). '
772 'Note this will quite heavily slow down the build. '
773 'This option implies --create --nousepkg.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400774 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700775 '-r',
776 '--replace',
777 action='store_true',
778 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500779 help='Replace an existing SDK chroot. Basically an alias '
780 'for --delete --create.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400781 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700782 '--delete',
783 action='store_true',
784 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500785 help='Delete the current SDK chroot if it exists.')
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400786 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700787 '--unmount',
788 action='store_true',
789 default=False,
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600790 help='Unmount and clean up devices associated with the '
791 'SDK chroot if it exists. This does not delete the '
792 'backing image file, so the same chroot can be later '
793 're-mounted for reuse. To fully delete the chroot, use '
794 '--delete. This is primarily useful for working on '
795 'cros_sdk or the chroot setup; you should not need it '
796 'under normal circumstances.')
797 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700798 '--download',
799 action='store_true',
800 default=False,
Mike Frysinger34db8692013-11-11 14:54:08 -0500801 help='Download the sdk.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600802 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700803 '--snapshot-create',
804 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600805 help='Create a snapshot of the chroot. Requires that the chroot was '
Manoj Guptab12f7302019-06-03 16:40:14 -0700806 'created without the --nouse-image option.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600807 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700808 '--snapshot-restore',
809 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600810 help='Restore the chroot to a previously created snapshot.')
811 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700812 '--snapshot-delete',
813 metavar='SNAPSHOT_NAME',
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600814 help='Delete a previously created snapshot. Deleting a snapshot that '
Manoj Guptab12f7302019-06-03 16:40:14 -0700815 'does not exist is not an error.')
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600816 group.add_argument(
Manoj Guptab12f7302019-06-03 16:40:14 -0700817 '--snapshot-list',
818 action='store_true',
819 default=False,
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600820 help='List existing snapshots of the chroot and exit.')
Mike Frysinger34db8692013-11-11 14:54:08 -0500821 commands = group
822
Mike Frysinger80dfce92014-04-21 10:58:53 -0400823 # Namespace options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400824 group = parser.add_argument_group('Namespaces')
Manoj Guptab12f7302019-06-03 16:40:14 -0700825 group.add_argument(
826 '--proxy-sim',
827 action='store_true',
828 default=False,
829 help='Simulate a restrictive network requiring an outbound'
830 ' proxy.')
831 group.add_argument(
832 '--no-ns-pid',
833 dest='ns_pid',
834 default=True,
835 action='store_false',
836 help='Do not create a new PID namespace.')
Mike Frysinger80dfce92014-04-21 10:58:53 -0400837
Mike Frysinger34db8692013-11-11 14:54:08 -0500838 # Internal options.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400839 group = parser.add_argument_group(
Mike Frysinger34db8692013-11-11 14:54:08 -0500840 'Internal Chromium OS Build Team Options',
841 'Caution: these are for meant for the Chromium OS build team only')
Manoj Guptab12f7302019-06-03 16:40:14 -0700842 group.add_argument(
843 '--buildbot-log-version',
844 default=False,
845 action='store_true',
846 help='Log SDK version for buildbot consumption')
Mike Frysinger34db8692013-11-11 14:54:08 -0500847
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400848 return parser, commands
Mike Frysinger34db8692013-11-11 14:54:08 -0500849
850
851def main(argv):
Mike Frysingere652ba12019-09-08 00:57:43 -0400852 conf = key_value_store.LoadFile(
Mike Frysinger34db8692013-11-11 14:54:08 -0500853 os.path.join(constants.SOURCE_ROOT, constants.SDK_VERSION_FILE),
854 ignore_missing=True)
855 sdk_latest_version = conf.get('SDK_LATEST_VERSION', '<unknown>')
Manoj Gupta01927c12019-05-13 17:33:14 -0700856 bootstrap_frozen_version = conf.get('BOOTSTRAP_FROZEN_VERSION', '<unknown>')
Manoj Gupta55a63092019-06-13 11:47:13 -0700857
858 # Use latest SDK for bootstrapping if requested. Use a frozen version of SDK
859 # for bootstrapping if BOOTSTRAP_FROZEN_VERSION is set.
860 bootstrap_latest_version = (
861 sdk_latest_version
862 if bootstrap_frozen_version == '<unknown>' else bootstrap_frozen_version)
Mike Frysinger34db8692013-11-11 14:54:08 -0500863 parser, commands = _CreateParser(sdk_latest_version, bootstrap_latest_version)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400864 options = parser.parse_args(argv)
865 chroot_command = options.commands
Brian Harringb938c782012-02-29 15:14:38 -0800866
867 # Some sanity checks first, before we ask for sudo credentials.
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500868 cros_build_lib.AssertOutsideChroot()
Brian Harringb938c782012-02-29 15:14:38 -0800869
Brian Harring1790ac42012-09-23 08:53:33 -0700870 host = os.uname()[4]
Brian Harring1790ac42012-09-23 08:53:33 -0700871 if host != 'x86_64':
Benjamin Gordon040a1162017-06-29 13:44:47 -0600872 cros_build_lib.Die(
Brian Harring1790ac42012-09-23 08:53:33 -0700873 "cros_sdk is currently only supported on x86_64; you're running"
Mike Frysinger80de5012019-08-01 14:10:53 -0400874 ' %s. Please find a x86_64 machine.' % (host,))
Brian Harring1790ac42012-09-23 08:53:33 -0700875
Josh Triplett472a4182013-03-08 11:48:57 -0800876 _ReportMissing(osutils.FindMissingBinaries(NEEDED_TOOLS))
877 if options.proxy_sim:
878 _ReportMissing(osutils.FindMissingBinaries(PROXY_NEEDED_TOOLS))
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600879 missing_image_tools = osutils.FindMissingBinaries(IMAGE_NEEDED_TOOLS)
Brian Harringb938c782012-02-29 15:14:38 -0800880
Benjamin Gordon040a1162017-06-29 13:44:47 -0600881 if (sdk_latest_version == '<unknown>' or
882 bootstrap_latest_version == '<unknown>'):
883 cros_build_lib.Die(
884 'No SDK version was found. '
885 'Are you in a Chromium source tree instead of Chromium OS?\n\n'
886 'Please change to a directory inside your Chromium OS source tree\n'
887 'and retry. If you need to setup a Chromium OS source tree, see\n'
Mike Frysingerdcad4e02018-08-03 16:20:02 -0400888 ' https://dev.chromium.org/chromium-os/developer-guide')
Benjamin Gordon040a1162017-06-29 13:44:47 -0600889
Manoj Guptab12f7302019-06-03 16:40:14 -0700890 any_snapshot_operation = (
891 options.snapshot_create or options.snapshot_restore or
892 options.snapshot_delete or options.snapshot_list)
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600893 if any_snapshot_operation and not options.use_image:
894 cros_build_lib.Die('Snapshot operations are not compatible with '
895 '--nouse-image.')
896
Manoj Guptab12f7302019-06-03 16:40:14 -0700897 if (options.snapshot_delete and
898 options.snapshot_delete == options.snapshot_restore):
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600899 parser.error('Cannot --snapshot_delete the same snapshot you are '
900 'restoring with --snapshot_restore.')
901
David James471532c2013-01-21 10:23:31 -0800902 _ReExecuteIfNeeded([sys.argv[0]] + argv)
903
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600904 lock_path = os.path.dirname(options.chroot)
905 lock_path = os.path.join(
906 lock_path, '.%s_lock' % os.path.basename(options.chroot).lstrip('.'))
907
Brian Harring218e13c2012-10-10 16:21:26 -0700908 # Expand out the aliases...
909 if options.replace:
910 options.delete = options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800911
Brian Harring218e13c2012-10-10 16:21:26 -0700912 if options.bootstrap:
913 options.create = True
Brian Harringb938c782012-02-29 15:14:38 -0800914
Brian Harring218e13c2012-10-10 16:21:26 -0700915 # If a command is not given, default to enter.
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400916 # pylint: disable=protected-access
917 # This _group_actions access sucks, but upstream decided to not include an
918 # alternative to optparse's option_list, and this is what they recommend.
Manoj Guptab12f7302019-06-03 16:40:14 -0700919 options.enter |= not any(
920 getattr(options, x.dest) for x in commands._group_actions)
Mike Frysinger2f95cfc2015-06-04 04:00:26 -0400921 # pylint: enable=protected-access
Brian Harring218e13c2012-10-10 16:21:26 -0700922 options.enter |= bool(chroot_command)
923
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600924 if (options.delete and not options.create and
925 (options.enter or any_snapshot_operation)):
Mike Frysinger80de5012019-08-01 14:10:53 -0400926 parser.error('Trying to enter or snapshot the chroot when --delete '
927 'was specified makes no sense.')
Brian Harring218e13c2012-10-10 16:21:26 -0700928
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600929 if (options.unmount and
930 (options.create or options.enter or any_snapshot_operation)):
931 parser.error('--unmount cannot be specified with other chroot actions.')
932
Yong Hong84ba9172018-02-07 01:37:42 +0800933 if options.working_dir is not None and not os.path.isabs(options.working_dir):
934 options.working_dir = path_util.ToChrootPath(options.working_dir)
935
Benjamin Gordon35194f12017-07-19 10:26:22 -0600936 # Discern if we need to create the chroot.
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600937 chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600938 if (options.use_image and not chroot_exists and not options.delete and
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600939 not options.unmount and not missing_image_tools and
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600940 os.path.exists(_ImageFileForChroot(options.chroot))):
941 # Try to re-mount an existing image in case the user has rebooted.
942 with cgroups.SimpleContainChildren('cros_sdk'):
943 with locking.FileLock(lock_path, 'chroot lock') as lock:
944 logging.debug('Checking if existing chroot image can be mounted.')
945 lock.write_lock()
Benjamin Gordon74645232018-05-04 17:40:42 -0600946 cros_sdk_lib.MountChroot(options.chroot, create=False)
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600947 chroot_exists = cros_sdk_lib.IsChrootReady(options.chroot)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600948 if chroot_exists:
949 logging.notice('Mounted existing image %s on chroot',
950 _ImageFileForChroot(options.chroot))
Brian Harring218e13c2012-10-10 16:21:26 -0700951
952 # Finally, flip create if necessary.
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600953 if options.enter or options.snapshot_create:
Brian Harring218e13c2012-10-10 16:21:26 -0700954 options.create |= not chroot_exists
Brian Harringb938c782012-02-29 15:14:38 -0800955
Benjamin Gordon7b44bef2018-06-08 08:13:59 -0600956 # Make sure we will download if we plan to create.
957 options.download |= options.create
958
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600959 # Anything that needs to manipulate the main chroot mount or communicate with
960 # LVM needs to be done here before we enter the new namespaces.
961
962 # If deleting, do it regardless of the use_image flag so that a
963 # previously-created loopback chroot can also be cleaned up.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600964 # TODO(bmgordon): See if the DeleteChroot call below can be removed in
965 # favor of this block.
966 chroot_deleted = False
Benjamin Gordon386b9eb2017-07-20 09:21:33 -0600967 if options.delete:
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600968 with cgroups.SimpleContainChildren('cros_sdk'):
969 with locking.FileLock(lock_path, 'chroot lock') as lock:
970 lock.write_lock()
971 if missing_image_tools:
972 logging.notice('Unmounting chroot.')
973 osutils.UmountTree(options.chroot)
974 else:
975 logging.notice('Deleting chroot.')
Don Garrett36650112018-06-28 15:54:34 -0700976 cros_sdk_lib.CleanupChrootMount(options.chroot, delete=True)
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600977 chroot_deleted = True
978
Benjamin Gordon64a3f8d2018-06-08 10:34:39 -0600979 # If cleanup was requested, we have to do it while we're still in the original
980 # namespace. Since cleaning up the mount will interfere with any other
981 # commands, we exit here. The check above should have made sure that no other
982 # action was requested, anyway.
983 if options.unmount:
984 with locking.FileLock(lock_path, 'chroot lock') as lock:
985 lock.write_lock()
986 CleanupChroot(options.chroot)
987 sys.exit(0)
988
Benjamin Gordon2d7bf582017-07-12 10:11:26 -0600989 # Make sure the main chroot mount is visible. Contents will be filled in
990 # below if needed.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600991 if options.create and options.use_image:
992 if missing_image_tools:
Mike Frysinger80de5012019-08-01 14:10:53 -0400993 raise SystemExit("""The tool(s) %s were not found.
Benjamin Gordonabb3e372017-08-09 10:21:05 -0600994Please make sure the lvm2 and thin-provisioning-tools packages
995are installed on your host.
996Example(ubuntu):
997 sudo apt-get install lvm2 thin-provisioning-tools
998
999If you want to run without lvm2, pass --nouse-image (chroot
Mike Frysinger80de5012019-08-01 14:10:53 -04001000snapshots will be unavailable).""" % ', '.join(missing_image_tools))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001001
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001002 logging.debug('Making sure chroot image is mounted.')
1003 with cgroups.SimpleContainChildren('cros_sdk'):
1004 with locking.FileLock(lock_path, 'chroot lock') as lock:
1005 lock.write_lock()
Benjamin Gordon74645232018-05-04 17:40:42 -06001006 if not cros_sdk_lib.MountChroot(options.chroot, create=True):
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001007 cros_build_lib.Die('Unable to mount %s on chroot',
1008 _ImageFileForChroot(options.chroot))
1009 logging.notice('Mounted %s on chroot',
1010 _ImageFileForChroot(options.chroot))
Benjamin Gordon386b9eb2017-07-20 09:21:33 -06001011
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001012 # Snapshot operations will always need the VG/LV, but other actions won't.
1013 if any_snapshot_operation:
1014 with cgroups.SimpleContainChildren('cros_sdk'):
1015 with locking.FileLock(lock_path, 'chroot lock') as lock:
Benjamin Gordon74645232018-05-04 17:40:42 -06001016 chroot_vg, chroot_lv = cros_sdk_lib.FindChrootMountSource(
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001017 options.chroot)
1018 if not chroot_vg or not chroot_lv:
1019 cros_build_lib.Die('Unable to find VG/LV for chroot %s',
1020 options.chroot)
1021
1022 # Delete snapshot before creating a new one. This allows the user to
1023 # throw out old state, create a new snapshot, and enter the chroot in a
1024 # single call to cros_sdk. Since restore involves deleting, also do it
1025 # before creating.
1026 if options.snapshot_restore:
1027 lock.write_lock()
1028 valid_snapshots = ListChrootSnapshots(chroot_vg, chroot_lv)
1029 if options.snapshot_restore not in valid_snapshots:
Manoj Guptab12f7302019-06-03 16:40:14 -07001030 cros_build_lib.Die(
1031 '%s is not a valid snapshot to restore to. '
1032 'Valid snapshots: %s', options.snapshot_restore,
1033 ', '.join(valid_snapshots))
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001034 osutils.UmountTree(options.chroot)
1035 if not RestoreChrootSnapshot(options.snapshot_restore, chroot_vg,
1036 chroot_lv):
1037 cros_build_lib.Die('Unable to restore chroot to snapshot.')
Benjamin Gordon74645232018-05-04 17:40:42 -06001038 if not cros_sdk_lib.MountChroot(options.chroot, create=False):
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001039 cros_build_lib.Die('Unable to mount restored snapshot onto chroot.')
1040
1041 # Use a read lock for snapshot delete and create even though they modify
1042 # the filesystem, because they don't modify the mounted chroot itself.
1043 # The underlying LVM commands take their own locks, so conflicting
1044 # concurrent operations here may crash cros_sdk, but won't corrupt the
1045 # chroot image. This tradeoff seems worth it to allow snapshot
1046 # operations on chroots that have a process inside.
1047 if options.snapshot_delete:
1048 lock.read_lock()
1049 DeleteChrootSnapshot(options.snapshot_delete, chroot_vg, chroot_lv)
1050
1051 if options.snapshot_create:
1052 lock.read_lock()
1053 if not CreateChrootSnapshot(options.snapshot_create, chroot_vg,
1054 chroot_lv):
1055 cros_build_lib.Die('Unable to create snapshot.')
1056
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001057 img_path = _ImageFileForChroot(options.chroot)
1058 if (options.use_image and os.path.exists(options.chroot) and
1059 os.path.exists(img_path)):
1060 img_stat = os.stat(img_path)
1061 img_used_bytes = img_stat.st_blocks * 512
1062
1063 mount_stat = os.statvfs(options.chroot)
Manoj Guptab12f7302019-06-03 16:40:14 -07001064 mount_used_bytes = mount_stat.f_frsize * (
1065 mount_stat.f_blocks - mount_stat.f_bfree)
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001066
Mike Frysinger93e8ffa2019-07-03 20:24:18 -04001067 extra_gbs = (img_used_bytes - mount_used_bytes) // 2**30
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001068 if extra_gbs > MAX_UNUSED_IMAGE_GBS:
1069 logging.notice('%s is using %s GiB more than needed. Running '
1070 'fstrim.', img_path, extra_gbs)
1071 cmd = ['fstrim', options.chroot]
1072 try:
1073 cros_build_lib.RunCommand(cmd, print_cmd=False)
1074 except cros_build_lib.RunCommandError as e:
Manoj Guptab12f7302019-06-03 16:40:14 -07001075 logging.warning(
1076 'Running fstrim failed. Consider running fstrim on '
1077 'your chroot manually.\nError: %s', e)
Benjamin Gordone3d5bd12017-11-16 15:42:28 -07001078
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001079 # Enter a new set of namespaces. Everything after here cannot directly affect
1080 # the hosts's mounts or alter LVM volumes.
Benjamin Gordon386b9eb2017-07-20 09:21:33 -06001081 namespaces.SimpleUnshare()
1082 if options.ns_pid:
1083 first_pid = namespaces.CreatePidNs()
1084 else:
1085 first_pid = None
1086
Benjamin Gordon2d7bf582017-07-12 10:11:26 -06001087 if options.snapshot_list:
1088 for snap in ListChrootSnapshots(chroot_vg, chroot_lv):
1089 print(snap)
1090 sys.exit(0)
1091
Brian Harringb938c782012-02-29 15:14:38 -08001092 if not options.sdk_version:
Manoj Guptab12f7302019-06-03 16:40:14 -07001093 sdk_version = (
1094 bootstrap_latest_version if options.bootstrap else sdk_latest_version)
Brian Harringb938c782012-02-29 15:14:38 -08001095 else:
1096 sdk_version = options.sdk_version
Mike Frysinger34db8692013-11-11 14:54:08 -05001097 if options.buildbot_log_version:
Prathmesh Prabhu17f07422015-07-17 11:40:40 -07001098 logging.PrintBuildbotStepText(sdk_version)
Brian Harringb938c782012-02-29 15:14:38 -08001099
Gilad Arnoldecc86fa2015-05-22 12:06:04 -07001100 # Based on selections, determine the tarball to fetch.
Yong Hong4e29b622018-02-05 14:31:10 +08001101 if options.download:
1102 if options.sdk_url:
1103 urls = [options.sdk_url]
Yong Hong4e29b622018-02-05 14:31:10 +08001104 else:
1105 urls = GetArchStageTarballs(sdk_version)
Brian Harring1790ac42012-09-23 08:53:33 -07001106
Mike Frysinger80dfce92014-04-21 10:58:53 -04001107 with cgroups.SimpleContainChildren('cros_sdk', pid=first_pid):
David James56e6c2c2012-10-24 23:54:41 -07001108 with locking.FileLock(lock_path, 'chroot lock') as lock:
Josh Triplett472a4182013-03-08 11:48:57 -08001109 if options.proxy_sim:
1110 _ProxySimSetup(options)
1111
Benjamin Gordonabb3e372017-08-09 10:21:05 -06001112 if (options.delete and not chroot_deleted and
1113 (os.path.exists(options.chroot) or
1114 os.path.exists(_ImageFileForChroot(options.chroot)))):
David James56e6c2c2012-10-24 23:54:41 -07001115 lock.write_lock()
1116 DeleteChroot(options.chroot)
Brian Harringb938c782012-02-29 15:14:38 -08001117
David James56e6c2c2012-10-24 23:54:41 -07001118 sdk_cache = os.path.join(options.cache_dir, 'sdks')
1119 distfiles_cache = os.path.join(options.cache_dir, 'distfiles')
Yu-Ju Hong2c066762013-10-28 14:05:08 -07001120 osutils.SafeMakedirsNonRoot(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -07001121
David James56e6c2c2012-10-24 23:54:41 -07001122 for target in (sdk_cache, distfiles_cache):
Mike Frysinger648ba2d2013-01-08 14:19:34 -05001123 src = os.path.join(constants.SOURCE_ROOT, os.path.basename(target))
David James56e6c2c2012-10-24 23:54:41 -07001124 if not os.path.exists(src):
Prathmesh Prabhu06a50562016-10-22 01:41:44 -07001125 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -07001126 continue
1127 lock.write_lock(
Mike Frysinger80de5012019-08-01 14:10:53 -04001128 'Upgrade to %r needed but chroot is locked; please exit '
1129 'all instances so this upgrade can finish.' % src)
David James56e6c2c2012-10-24 23:54:41 -07001130 if not os.path.exists(src):
1131 # Note that while waiting for the write lock, src may've vanished;
1132 # it's a rare race during the upgrade process that's a byproduct
1133 # of us avoiding taking a write lock to do the src check. If we
1134 # took a write lock for that check, it would effectively limit
1135 # all cros_sdk for a chroot to a single instance.
Prathmesh Prabhu06a50562016-10-22 01:41:44 -07001136 osutils.SafeMakedirsNonRoot(target)
David James56e6c2c2012-10-24 23:54:41 -07001137 elif not os.path.exists(target):
1138 # Upgrade occurred, but a reversion, or something whacky
1139 # occurred writing to the old location. Wipe and continue.
1140 os.rename(src, target)
1141 else:
1142 # Upgrade occurred once already, but either a reversion or
1143 # some before/after separate cros_sdk usage is at play.
1144 # Wipe and continue.
1145 osutils.RmDir(src)
Brian Harringae0a5322012-09-15 01:46:51 -07001146
David James56e6c2c2012-10-24 23:54:41 -07001147 if options.download:
1148 lock.write_lock()
Gilad Arnold6a8f0452015-06-04 11:25:18 -07001149 sdk_tarball = FetchRemoteTarballs(
1150 sdk_cache, urls, 'stage3' if options.bootstrap else 'SDK')
Brian Harring218e13c2012-10-10 16:21:26 -07001151
David James56e6c2c2012-10-24 23:54:41 -07001152 if options.create:
1153 lock.write_lock()
Benjamin Gordon7b44bef2018-06-08 08:13:59 -06001154 # Recheck if the chroot is set up here before creating to make sure we
1155 # account for whatever the various delete/unmount/remount steps above
1156 # have done.
1157 if cros_sdk_lib.IsChrootReady(options.chroot):
1158 logging.debug('Chroot already exists. Skipping creation.')
1159 else:
Manoj Guptab12f7302019-06-03 16:40:14 -07001160 CreateChroot(
1161 options.chroot,
1162 sdk_tarball,
1163 options.cache_dir,
1164 nousepkg=(options.bootstrap or options.nousepkg))
Brian Harring1790ac42012-09-23 08:53:33 -07001165
David James56e6c2c2012-10-24 23:54:41 -07001166 if options.enter:
1167 lock.read_lock()
1168 EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
Mike Frysinger0b2d9ee2019-02-28 17:05:47 -05001169 options.chrome_root_mount, options.goma_dir,
1170 options.goma_client_json, options.working_dir,
1171 chroot_command)