blob: eced9fe5eae9a6db1624c1c819529c5d9da8dd19 [file] [log] [blame]
Xiaochu Liudeed0232018-06-26 10:25:34 -07001# -*- coding: utf-8 -*-
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Xiaochu Liudeed0232018-06-26 10:25:34 -07005"""Script to generate a DLC (Downloadable Content) artifact."""
6
Mike Frysinger93e8ffa2019-07-03 20:24:18 -04007from __future__ import division
Xiaochu Liudeed0232018-06-26 10:25:34 -07008from __future__ import print_function
9
10import hashlib
11import json
12import math
13import os
Amin Hassanibc1a4792019-10-24 14:39:57 -070014import re
Amin Hassani11a88cf2019-01-29 15:31:24 -080015import shutil
Andreweff865f2020-04-24 13:39:44 -070016import sys
Xiaochu Liudeed0232018-06-26 10:25:34 -070017
18from chromite.lib import commandline
19from chromite.lib import cros_build_lib
Amin Hassanib97a5ee2019-01-23 14:44:43 -080020from chromite.lib import cros_logging as logging
Xiaochu Liudeed0232018-06-26 10:25:34 -070021from chromite.lib import osutils
22
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080023from chromite.scripts import cros_set_lsb_release
Xiaochu Liudeed0232018-06-26 10:25:34 -070024
Andreweff865f2020-04-24 13:39:44 -070025assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
26
Amin Hassani2af75a92019-01-22 21:07:45 -080027DLC_META_DIR = 'opt/google/dlc/'
Andrew67b5fa72020-02-05 14:14:48 -080028DLC_TMP_META_DIR = 'meta'
29DLC_BUILD_DIR = 'build/rootfs/dlc/'
Amin Hassanid5742d32019-01-22 21:13:34 -080030LSB_RELEASE = 'etc/lsb-release'
Jae Hoon Kim5f411e42020-01-09 13:30:56 -080031DLC_IMAGE = 'dlc.img'
32IMAGELOADER_JSON = 'imageloader.json'
Andrew67b5fa72020-02-05 14:14:48 -080033EBUILD_PARAMETERS = 'ebuild_parameters.json'
Amin Hassanid5742d32019-01-22 21:13:34 -080034
Amin Hassani11a88cf2019-01-29 15:31:24 -080035# This file has major and minor version numbers that the update_engine client
36# supports. These values are needed for generating a delta/full payload.
37UPDATE_ENGINE_CONF = 'etc/update_engine.conf'
38
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -080039_EXTRA_RESOURCES = (UPDATE_ENGINE_CONF,)
Amin Hassani11a88cf2019-01-29 15:31:24 -080040
Amin Hassanid5742d32019-01-22 21:13:34 -080041DLC_ID_KEY = 'DLC_ID'
Amin Hassanib5a48042019-03-18 14:30:51 -070042DLC_PACKAGE_KEY = 'DLC_PACKAGE'
Amin Hassanid5742d32019-01-22 21:13:34 -080043DLC_NAME_KEY = 'DLC_NAME'
Amin Hassani8f1cc0f2019-03-06 15:34:53 -080044DLC_APPID_KEY = 'DLC_RELEASE_APPID'
Amin Hassani2af75a92019-01-22 21:07:45 -080045
Amin Hassani22a25eb2019-01-11 14:25:02 -080046_SQUASHFS_TYPE = 'squashfs'
47_EXT4_TYPE = 'ext4'
48
Amin Hassani160e12e2020-04-13 14:29:36 -070049_USED_BY_USER = 'user'
50_USED_BY_SYSTEM = 'system'
51
Amin Hassanibc1a4792019-10-24 14:39:57 -070052MAX_ID_NAME = 40
Amin Hassanid5742d32019-01-22 21:13:34 -080053
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -080054
Xiaochu Liudeed0232018-06-26 10:25:34 -070055def HashFile(file_path):
56 """Calculate the sha256 hash of a file.
57
58 Args:
59 file_path: (str) path to the file.
60
61 Returns:
62 [str]: The sha256 hash of the file.
63 """
64 sha256 = hashlib.sha256()
65 with open(file_path, 'rb') as f:
66 for b in iter(lambda: f.read(2048), b''):
67 sha256.update(b)
68 return sha256.hexdigest()
69
70
Jae Hoon Kim5f411e42020-01-09 13:30:56 -080071def GetValueInJsonFile(json_path, key, default_value=None):
72 """Reads file containing JSON and returns value or default_value for key.
73
74 Args:
75 json_path: (str) File containing JSON.
76 key: (str) The desired key to lookup.
77 default_value: (default:None) The default value returned in case of missing
78 key.
79 """
80 with open(json_path) as fd:
81 return json.load(fd).get(key, default_value)
82
83
Andrew67b5fa72020-02-05 14:14:48 -080084class EbuildParams(object):
85 """Object to store and retrieve DLC ebuild parameters.
86
87 Attributes:
88 dlc_id: (str) DLC ID.
89 dlc_package: (str) DLC package.
90 fs_type: (str) file system type.
91 pre_allocated_blocks: (int) number of blocks pre-allocated on device.
92 version: (str) DLC version.
93 name: (str) DLC name.
Jae Hoon Kim6ef63172020-04-06 12:39:04 -070094 description: (str) DLC description.
Andrew67b5fa72020-02-05 14:14:48 -080095 preload: (bool) allow for preloading DLC.
Amin Hassani160e12e2020-04-13 14:29:36 -070096 used_by: (str) The user of this DLC, e.g. "system" or "user"
Andrew67b5fa72020-02-05 14:14:48 -080097 """
98
99 def __init__(self, dlc_id, dlc_package, fs_type, pre_allocated_blocks,
Amin Hassani160e12e2020-04-13 14:29:36 -0700100 version, name, description, preload, used_by):
Andrew67b5fa72020-02-05 14:14:48 -0800101 self.dlc_id = dlc_id
102 self.dlc_package = dlc_package
103 self.fs_type = fs_type
104 self.pre_allocated_blocks = pre_allocated_blocks
105 self.version = version
106 self.name = name
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700107 self.description = description
Andrew67b5fa72020-02-05 14:14:48 -0800108 self.preload = preload
Amin Hassani160e12e2020-04-13 14:29:36 -0700109 self.used_by = used_by
Andrew67b5fa72020-02-05 14:14:48 -0800110
111 def StoreDlcParameters(self, install_root_dir, sudo):
112 """Store DLC parameters defined in the ebuild.
113
114 Store DLC parameters defined in the ebuild in a temporary file so they can
115 be retrieved in the build_image phase.
116
117 Args:
118 install_root_dir: (str) The path to the root installation directory.
119 sudo: (bool) Use sudo to write the file.
120 """
121 ebuild_params_path = EbuildParams.GetParamsPath(install_root_dir,
122 self.dlc_id,
123 self.dlc_package)
124 osutils.WriteFile(ebuild_params_path,
125 json.dumps(self.__dict__),
126 makedirs=True, sudo=sudo)
127
128 @staticmethod
129 def GetParamsPath(install_root_dir, dlc_id, dlc_package):
130 """Get the path to the file storing the ebuild parameters.
131
132 Args:
133 install_root_dir: (str) The path to the root installation directory.
134 dlc_id: (str) DLC ID.
135 dlc_package: (str) DLC package.
136
137 Returns:
138 [str]: Path to |EBUILD_PARAMETERS|.
139 """
140 return os.path.join(install_root_dir, DLC_BUILD_DIR, dlc_id, dlc_package,
141 EBUILD_PARAMETERS)
142
143 @classmethod
Jae Hoon Kim264b8d22020-04-06 11:49:19 -0700144 def LoadEbuildParams(cls, sysroot, dlc_id, dlc_package):
Andrew67b5fa72020-02-05 14:14:48 -0800145 """Read the stored ebuild parameters file and return a class instance.
146
147 Args:
148 dlc_id: (str) DLC ID.
149 dlc_package: (str) DLC package.
150 sysroot: (str) The path to the build root directory.
151
152 Returns:
153 [bool] : True if |ebuild_params_path| exists, False otherwise.
154 """
155 path = cls.GetParamsPath(sysroot, dlc_id, dlc_package)
156 if not os.path.exists(path):
157 return None
158
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700159 with open(path, 'rb') as fp:
Andrew67b5fa72020-02-05 14:14:48 -0800160 return cls(**json.load(fp))
161
162 def __str__(self):
163 return str(self.__dict__)
164
165
Amin Hassani174eb7e2019-01-18 11:11:24 -0800166class DlcGenerator(object):
Xiaochu Liudeed0232018-06-26 10:25:34 -0700167 """Object to generate DLC artifacts."""
168 # Block size for the DLC image.
169 # We use 4K for various reasons:
170 # 1. it's what imageloader (linux kernel) supports.
171 # 2. it's what verity supports.
172 _BLOCK_SIZE = 4096
173 # Blocks in the initial sparse image.
174 _BLOCKS = 500000
175 # Version of manifest file.
176 _MANIFEST_VERSION = 1
177
Amin Hassanicc7ffce2019-01-11 14:57:52 -0800178 # The DLC root path inside the DLC module.
179 _DLC_ROOT_DIR = 'root'
180
Andrew67b5fa72020-02-05 14:14:48 -0800181 def __init__(self, ebuild_params, sysroot, install_root_dir, src_dir=None):
Xiaochu Liudeed0232018-06-26 10:25:34 -0700182 """Object initializer.
183
184 Args:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800185 sysroot: (str) The path to the build root directory.
Amin Hassani2af75a92019-01-22 21:07:45 -0800186 install_root_dir: (str) The path to the root installation directory.
Andrew67b5fa72020-02-05 14:14:48 -0800187 ebuild_params: (EbuildParams) Ebuild variables.
188 src_dir: (str) Optional path to the DLC source root directory. When None,
189 the default directory in |DLC_BUILD_DIR| is used.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700190 """
Andrew67b5fa72020-02-05 14:14:48 -0800191 # Use a temporary directory to avoid having to use sudo every time we write
192 # into the build directory.
193 self.temp_root = osutils.TempDir(prefix='dlc', sudo_rm=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700194 self.src_dir = src_dir
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800195 self.sysroot = sysroot
Amin Hassani2af75a92019-01-22 21:07:45 -0800196 self.install_root_dir = install_root_dir
Andrew67b5fa72020-02-05 14:14:48 -0800197 self.ebuild_params = ebuild_params
198 # If the client is not overriding the src_dir, use the default one.
199 if not self.src_dir:
200 self.src_dir = os.path.join(self.sysroot, DLC_BUILD_DIR,
201 self.ebuild_params.dlc_id,
202 self.ebuild_params.dlc_package,
203 self._DLC_ROOT_DIR)
Amin Hassani2af75a92019-01-22 21:07:45 -0800204
Andrew67b5fa72020-02-05 14:14:48 -0800205 self.image_dir = os.path.join(self.temp_root.tempdir,
206 DLC_BUILD_DIR,
207 self.ebuild_params.dlc_id,
208 self.ebuild_params.dlc_package)
209
210 self.meta_dir = os.path.join(self.image_dir, DLC_TMP_META_DIR)
Amin Hassani2af75a92019-01-22 21:07:45 -0800211
Xiaochu Liudeed0232018-06-26 10:25:34 -0700212 # Create path for all final artifacts.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800213 self.dest_image = os.path.join(self.image_dir, DLC_IMAGE)
Amin Hassani2af75a92019-01-22 21:07:45 -0800214 self.dest_table = os.path.join(self.meta_dir, 'table')
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800215 self.dest_imageloader_json = os.path.join(self.meta_dir, IMAGELOADER_JSON)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700216
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700217 # Log out the member variable values initially set.
218 logging.debug('Initial internal values of DlcGenerator: %s',
Andrew67b5fa72020-02-05 14:14:48 -0800219 repr({k:str(i) for k, i in self.__dict__.items()}))
220
221 def CopyTempContentsToBuildDir(self):
222 """Copy the temp files to the build directory using sudo."""
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700223 src = self.temp_root.tempdir.rstrip('/') + '/.'
224 dst = self.install_root_dir
225 logging.info(
226 'Copy files from temporary directory (%s) to build directory (%s).',
227 src, dst)
228 cros_build_lib.sudo_run(['cp', '-dR', src, dst])
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700229
Xiaochu Liudeed0232018-06-26 10:25:34 -0700230 def SquashOwnerships(self, path):
231 """Squash the owernships & permissions for files.
232
233 Args:
234 path: (str) path that contains all files to be processed.
235 """
Mike Frysinger45602c72019-09-22 02:15:11 -0400236 cros_build_lib.sudo_run(['chown', '-R', '0:0', path])
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800237 cros_build_lib.sudo_run([
238 'find', path, '-exec', 'touch', '-h', '-t', '197001010000.00', '{}', '+'
239 ])
Xiaochu Liudeed0232018-06-26 10:25:34 -0700240
241 def CreateExt4Image(self):
242 """Create an ext4 image."""
243 with osutils.TempDir(prefix='dlc_') as temp_dir:
244 mount_point = os.path.join(temp_dir, 'mount_point')
Andrew67b5fa72020-02-05 14:14:48 -0800245 # Create the directory where the image is located if it doesn't exist.
246 osutils.SafeMakedirs(os.path.split(self.dest_image)[0])
Xiaochu Liudeed0232018-06-26 10:25:34 -0700247 # Create a raw image file.
248 with open(self.dest_image, 'w') as f:
249 f.truncate(self._BLOCKS * self._BLOCK_SIZE)
250 # Create an ext4 file system on the raw image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800251 cros_build_lib.run([
252 '/sbin/mkfs.ext4', '-b',
253 str(self._BLOCK_SIZE), '-O', '^has_journal', self.dest_image
254 ],
255 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700256 # Create the mount_point directory.
257 osutils.SafeMakedirs(mount_point)
258 # Mount the ext4 image.
259 osutils.MountDir(self.dest_image, mount_point, mount_opts=('loop', 'rw'))
Amin Hassanicc7ffce2019-01-11 14:57:52 -0800260
Xiaochu Liudeed0232018-06-26 10:25:34 -0700261 try:
Amin Hassani11a88cf2019-01-29 15:31:24 -0800262 self.SetupDlcImageFiles(mount_point)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700263 finally:
264 # Unmount the ext4 image.
265 osutils.UmountDir(mount_point)
266 # Shrink to minimum size.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800267 cros_build_lib.run(['/sbin/e2fsck', '-y', '-f', self.dest_image],
268 capture_output=True)
269 cros_build_lib.run(['/sbin/resize2fs', '-M', self.dest_image],
270 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700271
272 def CreateSquashfsImage(self):
273 """Create a squashfs image."""
274 with osutils.TempDir(prefix='dlc_') as temp_dir:
Amin Hassani22a25eb2019-01-11 14:25:02 -0800275 squashfs_root = os.path.join(temp_dir, 'squashfs-root')
Amin Hassani11a88cf2019-01-29 15:31:24 -0800276 self.SetupDlcImageFiles(squashfs_root)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800277
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800278 cros_build_lib.run([
279 'mksquashfs', squashfs_root, self.dest_image, '-4k-align', '-noappend'
280 ],
281 capture_output=True)
Amin Hassani22a25eb2019-01-11 14:25:02 -0800282
283 # We changed the ownership and permissions of the squashfs_root
284 # directory. Now we need to remove it manually.
285 osutils.RmDir(squashfs_root, sudo=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700286
Amin Hassani11a88cf2019-01-29 15:31:24 -0800287 def SetupDlcImageFiles(self, dlc_dir):
288 """Prepares the directory dlc_dir with all the files a DLC needs.
289
290 Args:
291 dlc_dir: (str) The path to where to setup files inside the DLC.
292 """
293 dlc_root_dir = os.path.join(dlc_dir, self._DLC_ROOT_DIR)
294 osutils.SafeMakedirs(dlc_root_dir)
Jae Hoon Kimd14646b2019-08-21 14:49:26 -0700295 osutils.CopyDirContents(self.src_dir, dlc_root_dir, symlinks=True)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800296 self.PrepareLsbRelease(dlc_dir)
297 self.CollectExtraResources(dlc_dir)
298 self.SquashOwnerships(dlc_dir)
299
Amin Hassanid5742d32019-01-22 21:13:34 -0800300 def PrepareLsbRelease(self, dlc_dir):
301 """Prepare the file /etc/lsb-release in the DLC module.
302
303 This file is used dropping some identification parameters for the DLC.
304
305 Args:
306 dlc_dir: (str) The path to root directory of the DLC. e.g. mounted point
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800307 when we are creating the image.
Amin Hassanid5742d32019-01-22 21:13:34 -0800308 """
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800309 # Reading the platform APPID and creating the DLC APPID.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800310 platform_lsb_release = osutils.ReadFile(
311 os.path.join(self.sysroot, LSB_RELEASE))
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800312 app_id = None
313 for line in platform_lsb_release.split('\n'):
314 if line.startswith(cros_set_lsb_release.LSB_KEY_APPID_RELEASE):
315 app_id = line.split('=')[1]
316 if app_id is None:
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800317 raise Exception(
318 '%s does not have a valid key %s' %
319 (platform_lsb_release, cros_set_lsb_release.LSB_KEY_APPID_RELEASE))
Amin Hassanid5742d32019-01-22 21:13:34 -0800320
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400321 fields = (
Andrew67b5fa72020-02-05 14:14:48 -0800322 (DLC_ID_KEY, self.ebuild_params.dlc_id),
323 (DLC_PACKAGE_KEY, self.ebuild_params.dlc_package),
324 (DLC_NAME_KEY, self.ebuild_params.name),
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800325 # The DLC appid is generated by concatenating the platform appid with
326 # the DLC ID using an underscore. This pattern should never be changed
327 # once set otherwise it can break a lot of things!
Andrew67b5fa72020-02-05 14:14:48 -0800328 (DLC_APPID_KEY, '%s_%s' % (app_id, self.ebuild_params.dlc_id)),
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400329 )
Amin Hassani8f1cc0f2019-03-06 15:34:53 -0800330
331 lsb_release = os.path.join(dlc_dir, LSB_RELEASE)
332 osutils.SafeMakedirs(os.path.dirname(lsb_release))
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400333 content = ''.join('%s=%s\n' % (k, v) for k, v in fields)
Amin Hassanid5742d32019-01-22 21:13:34 -0800334 osutils.WriteFile(lsb_release, content)
335
Amin Hassani11a88cf2019-01-29 15:31:24 -0800336 def CollectExtraResources(self, dlc_dir):
337 """Collect the extra resources needed by the DLC module.
338
339 Look at the documentation around _EXTRA_RESOURCES.
340
341 Args:
342 dlc_dir: (str) The path to root directory of the DLC. e.g. mounted point
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800343 when we are creating the image.
Amin Hassani11a88cf2019-01-29 15:31:24 -0800344 """
345 for r in _EXTRA_RESOURCES:
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800346 source_path = os.path.join(self.sysroot, r)
Amin Hassani11a88cf2019-01-29 15:31:24 -0800347 target_path = os.path.join(dlc_dir, r)
348 osutils.SafeMakedirs(os.path.dirname(target_path))
349 shutil.copyfile(source_path, target_path)
350
Xiaochu Liudeed0232018-06-26 10:25:34 -0700351 def CreateImage(self):
352 """Create the image and copy the DLC files to it."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700353 logging.info('Creating the DLC image.')
Andrew67b5fa72020-02-05 14:14:48 -0800354 if self.ebuild_params.fs_type == _EXT4_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700355 self.CreateExt4Image()
Andrew67b5fa72020-02-05 14:14:48 -0800356 elif self.ebuild_params.fs_type == _SQUASHFS_TYPE:
Xiaochu Liudeed0232018-06-26 10:25:34 -0700357 self.CreateSquashfsImage()
358 else:
Andrew67b5fa72020-02-05 14:14:48 -0800359 raise ValueError('Wrong fs type: %s used:' % self.ebuild_params.fs_type)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700360
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700361 def VerifyImageSize(self):
Xiaochu Liu36b30592019-08-06 09:39:54 -0700362 """Verify the image can fit to the reserved file."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700363 logging.info('Verifying the DLC image size.')
364 image_bytes = os.path.getsize(self.dest_image)
Andrew67b5fa72020-02-05 14:14:48 -0800365 preallocated_bytes = (self.ebuild_params.pre_allocated_blocks *
366 self._BLOCK_SIZE)
Xiaochu Liu36b30592019-08-06 09:39:54 -0700367 # Verifies the actual size of the DLC image is NOT smaller than the
368 # preallocated space.
369 if preallocated_bytes < image_bytes:
370 raise ValueError(
371 'The DLC_PREALLOC_BLOCKS (%s) value set in DLC ebuild resulted in a '
372 'max size of DLC_PREALLOC_BLOCKS * 4K (%s) bytes the DLC image is '
373 'allowed to occupy. The value is smaller than the actual image size '
374 '(%s) required. Increase DLC_PREALLOC_BLOCKS in your ebuild to at '
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800375 'least %d.' %
Andrew67b5fa72020-02-05 14:14:48 -0800376 (self.ebuild_params.pre_allocated_blocks, preallocated_bytes,
377 image_bytes, self.GetOptimalImageBlockSize(image_bytes)))
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700378
379 def GetOptimalImageBlockSize(self, image_bytes):
380 """Given the image bytes, get the least amount of blocks required."""
381 return int(math.ceil(image_bytes / self._BLOCK_SIZE))
Xiaochu Liu36b30592019-08-06 09:39:54 -0700382
Xiaochu Liudeed0232018-06-26 10:25:34 -0700383 def GetImageloaderJsonContent(self, image_hash, table_hash, blocks):
384 """Return the content of imageloader.json file.
385
386 Args:
387 image_hash: (str) sha256 hash of the DLC image.
388 table_hash: (str) sha256 hash of the DLC table file.
389 blocks: (int) number of blocks in the DLC image.
390
391 Returns:
392 [str]: content of imageloader.json file.
393 """
394 return {
Andrew67b5fa72020-02-05 14:14:48 -0800395 'fs-type': self.ebuild_params.fs_type,
396 'id': self.ebuild_params.dlc_id,
397 'package': self.ebuild_params.dlc_package,
Xiaochu Liudeed0232018-06-26 10:25:34 -0700398 'image-sha256-hash': image_hash,
399 'image-type': 'dlc',
400 'is-removable': True,
401 'manifest-version': self._MANIFEST_VERSION,
Andrew67b5fa72020-02-05 14:14:48 -0800402 'name': self.ebuild_params.name,
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700403 'description': self.ebuild_params.description,
Andrew67b5fa72020-02-05 14:14:48 -0800404 'pre-allocated-size':
405 str(self.ebuild_params.pre_allocated_blocks * self._BLOCK_SIZE),
Jae Hoon Kimbd8ae6e2020-02-03 18:54:29 -0800406 'size': str(blocks * self._BLOCK_SIZE),
Xiaochu Liudeed0232018-06-26 10:25:34 -0700407 'table-sha256-hash': table_hash,
Andrew67b5fa72020-02-05 14:14:48 -0800408 'version': self.ebuild_params.version,
409 'preload-allowed': self.ebuild_params.preload,
Amin Hassani160e12e2020-04-13 14:29:36 -0700410 'used-by': self.ebuild_params.used_by,
Xiaochu Liudeed0232018-06-26 10:25:34 -0700411 }
412
413 def GenerateVerity(self):
414 """Generate verity parameters and hashes for the image."""
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700415 logging.info('Generating DLC image verity.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700416 with osutils.TempDir(prefix='dlc_') as temp_dir:
417 hash_tree = os.path.join(temp_dir, 'hash_tree')
418 # Get blocks in the image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800419 blocks = math.ceil(os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
420 result = cros_build_lib.run([
421 'verity', 'mode=create', 'alg=sha256', 'payload=' + self.dest_image,
422 'payload_blocks=' + str(blocks), 'hashtree=' + hash_tree,
423 'salt=random'
424 ],
425 capture_output=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700426 table = result.output
427
428 # Append the merkle tree to the image.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800429 osutils.WriteFile(
430 self.dest_image, osutils.ReadFile(hash_tree, mode='rb'), mode='a+b')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700431
432 # Write verity parameter to table file.
Mike Frysinger1c834ea2019-10-14 04:29:41 -0400433 osutils.WriteFile(self.dest_table, table, mode='wb')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700434
435 # Compute image hash.
436 image_hash = HashFile(self.dest_image)
437 table_hash = HashFile(self.dest_table)
438 # Write image hash to imageloader.json file.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800439 blocks = math.ceil(os.path.getsize(self.dest_image) / self._BLOCK_SIZE)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700440 imageloader_json_content = self.GetImageloaderJsonContent(
441 image_hash, table_hash, int(blocks))
442 with open(self.dest_imageloader_json, 'w') as f:
443 json.dump(imageloader_json_content, f)
444
445 def GenerateDLC(self):
446 """Generate a DLC artifact."""
Andrew67b5fa72020-02-05 14:14:48 -0800447 # Create directories.
448 osutils.SafeMakedirs(self.image_dir)
449 osutils.SafeMakedirs(self.meta_dir)
450
451 # Create the image into |self.temp_root| and copy the DLC files to it.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700452 self.CreateImage()
Andrew67b5fa72020-02-05 14:14:48 -0800453 # Verify the image created is within pre-allocated size.
Jae Hoon Kime5b88622019-08-23 11:11:33 -0700454 self.VerifyImageSize()
Andrew67b5fa72020-02-05 14:14:48 -0800455 # Generate hash tree and other metadata and save them under
456 # |self.temp_root|.
Xiaochu Liudeed0232018-06-26 10:25:34 -0700457 self.GenerateVerity()
Andrew67b5fa72020-02-05 14:14:48 -0800458 # Copy the files from |self.temp_root| into the build directory.
459 self.CopyTempContentsToBuildDir()
460
461 # Now that the image was successfully generated, delete |ebuild_params_path|
462 # to indicate that the image in the build directory is in sync with the
463 # files installed during the build_package phase.
464 ebuild_params_path = EbuildParams.GetParamsPath(
465 self.sysroot, self.ebuild_params.dlc_id, self.ebuild_params.dlc_package)
466 osutils.SafeUnlink(ebuild_params_path, sudo=True)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700467
468
Andrew67b5fa72020-02-05 14:14:48 -0800469def IsDlcPreloadingAllowed(dlc_id, dlc_build_dir):
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800470 """Validates that DLC and it's packages all were built with DLC_PRELOAD=true.
471
472 Args:
473 dlc_id: (str) DLC ID.
Andrew67b5fa72020-02-05 14:14:48 -0800474 dlc_build_dir: (str) the root path where DLC build files reside.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800475 """
476
Andrew67b5fa72020-02-05 14:14:48 -0800477 dlc_id_meta_dir = os.path.join(dlc_build_dir, dlc_id)
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800478 if not os.path.exists(dlc_id_meta_dir):
Andrew67b5fa72020-02-05 14:14:48 -0800479 logging.error('DLC build directory (%s) does not exist for preloading '
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800480 'check, will not preload', dlc_id_meta_dir)
481 return False
482
483 packages = os.listdir(dlc_id_meta_dir)
484 if not packages:
Andrew67b5fa72020-02-05 14:14:48 -0800485 logging.error('DLC ID build directory (%s) does not have any '
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800486 'packages, will not preload.', dlc_id_meta_dir)
487 return False
488
Andrew67b5fa72020-02-05 14:14:48 -0800489 for package in packages:
490 image_loader_json = os.path.join(dlc_id_meta_dir, package, DLC_TMP_META_DIR,
491 IMAGELOADER_JSON)
492 if not os.path.exists(image_loader_json):
493 logging.error('DLC metadata file (%s) does not exist, will not preload.',
494 image_loader_json)
495 return False
496 if not GetValueInJsonFile(json_path=image_loader_json,
497 key='preload-allowed', default_value=False):
498 return False
499 # All packages support preload.
500 return True
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800501
502
Andrew67b5fa72020-02-05 14:14:48 -0800503def InstallDlcImages(sysroot, dlc_id=None, install_root_dir=None, preload=False,
504 rootfs=None, src_dir=None):
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800505 """Copies all DLC image files into the images directory.
506
507 Copies the DLC image files in the given build directory into the given DLC
508 image directory. If the DLC build directory does not exist, or there is no DLC
509 for that board, this function does nothing.
510
511 Args:
512 sysroot: Path to directory containing DLC images, e.g /build/<board>.
Andrew67b5fa72020-02-05 14:14:48 -0800513 dlc_id: (str) DLC ID. If None, all the DLCs will be installed.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800514 install_root_dir: Path to DLC output directory, e.g.
Andrew67b5fa72020-02-05 14:14:48 -0800515 src/build/images/<board>/<version>. If None, the image will be generated
516 but will not be copied to a destination.
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800517 preload: When true, only copies DLC(s) if built with DLC_PRELOAD=true.
Andrew67b5fa72020-02-05 14:14:48 -0800518 rootfs: (str) Path to the platform rootfs.
519 src_dir: (str) Path to the DLC source root directory.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800520 """
Andrew67b5fa72020-02-05 14:14:48 -0800521 dlc_build_dir = os.path.join(sysroot, DLC_BUILD_DIR)
522 if not os.path.exists(dlc_build_dir):
523 logging.info('DLC build directory (%s) does not exist, ignoring.',
524 dlc_build_dir)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800525 return
526
Andrew67b5fa72020-02-05 14:14:48 -0800527 if dlc_id is not None:
528 if not os.path.exists(os.path.join(dlc_build_dir, dlc_id)):
529 raise Exception(
530 'DLC "%s" does not exist in the build directory %s.' %
531 (dlc_id, dlc_build_dir))
532 dlc_ids = [dlc_id]
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800533 else:
Andrew67b5fa72020-02-05 14:14:48 -0800534 # Process all DLCs.
535 dlc_ids = os.listdir(dlc_build_dir)
536 if not dlc_ids:
537 logging.info('There are no DLC(s) to copy to output, ignoring.')
538 return
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800539
Andrew67b5fa72020-02-05 14:14:48 -0800540 logging.info('Detected the following DLCs: %s', ', '.join(dlc_ids))
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800541
Andrew67b5fa72020-02-05 14:14:48 -0800542 for d_id in dlc_ids:
543 dlc_id_path = os.path.join(dlc_build_dir, d_id)
544 dlc_packages = [direct for direct in os.listdir(dlc_id_path)
545 if os.path.isdir(os.path.join(dlc_id_path, direct))]
546 for d_package in dlc_packages:
547 logging.info('Building image: DLC %s', d_id)
Jae Hoon Kim264b8d22020-04-06 11:49:19 -0700548 params = EbuildParams.LoadEbuildParams(sysroot=sysroot, dlc_id=d_id,
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700549 dlc_package=d_package)
Andrew67b5fa72020-02-05 14:14:48 -0800550 # Because portage sandboxes every ebuild package during build_packages
551 # phase, we cannot delete the old image during that phase, but we can use
552 # the existence of the file |EBUILD_PARAMETERS| to know if the image
553 # has to be generated or not.
554 if not params:
555 logging.info('The ebuild parameters file (%s) for DLC (%s) does not '
556 'exist. This means that the image was already '
557 'generated and there is no need to create it again.',
558 EbuildParams.GetParamsPath(sysroot, d_id, d_package), d_id)
559 else:
560 dlc_generator = DlcGenerator(
561 src_dir=src_dir,
562 sysroot=sysroot,
563 install_root_dir=sysroot,
564 ebuild_params=params)
565 dlc_generator.GenerateDLC()
566
567 # Copy the dlc images to install_root_dir.
568 if install_root_dir:
569 if preload and not IsDlcPreloadingAllowed(d_id, dlc_build_dir):
570 logging.info('Skipping installation of DLC %s because the preload '
571 'flag is set and the DLC does not support preloading.',
572 d_id)
573 else:
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700574 osutils.SafeMakedirsNonRoot(install_root_dir)
Andrew67b5fa72020-02-05 14:14:48 -0800575 install_dlc_dir = os.path.join(install_root_dir, d_id, d_package)
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700576 osutils.SafeMakedirsNonRoot(install_dlc_dir)
577 source_dlc_dir = os.path.join(dlc_build_dir, d_id, d_package)
Andrew67b5fa72020-02-05 14:14:48 -0800578 for filepath in (os.path.join(source_dlc_dir, fname) for fname in
579 os.listdir(source_dlc_dir) if
580 fname.endswith('.img')):
581 logging.info('Copying DLC(%s) image from %s to %s: ', d_id,
582 filepath, install_dlc_dir)
Jae Hoon Kimb7da6fe2020-04-02 16:17:48 -0700583 shutil.copy(filepath, install_dlc_dir)
Andrew67b5fa72020-02-05 14:14:48 -0800584 logging.info('Done copying DLC to %s.', install_dlc_dir)
585 else:
586 logging.info('install_root_dir value was not provided. Copying dlc'
587 ' image skipped.')
588
589 # Create metadata directory in rootfs.
590 if rootfs:
591 meta_rootfs = os.path.join(rootfs, DLC_META_DIR, d_id, d_package)
592 osutils.SafeMakedirs(meta_rootfs, sudo=True)
593 # Copy the metadata files to rootfs.
594 meta_dir_src = os.path.join(dlc_build_dir, d_id, d_package,
595 DLC_TMP_META_DIR)
596 logging.info('Copying DLC(%s) metadata from %s to %s: ', d_id,
597 meta_dir_src, meta_rootfs)
598 # Use sudo_run since osutils.CopyDirContents doesn't support sudo.
599 cros_build_lib.sudo_run(['cp', '-dR',
600 meta_dir_src.rstrip('/') + '/.',
601 meta_rootfs], print_cmd=False, stderr=True)
602
603 else:
604 logging.info('rootfs value was not provided. Copying metadata skipped.')
605
606 logging.info('Done installing DLCs.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800607
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800608
Xiaochu Liudeed0232018-06-26 10:25:34 -0700609def GetParser():
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800610 """Creates an argument parser and returns it."""
Xiaochu Liudeed0232018-06-26 10:25:34 -0700611 parser = commandline.ArgumentParser(description=__doc__)
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800612 # This script is used both for building an individual DLC or copying all final
613 # DLCs images to their final destination nearby chromiumsos_test_image.bin,
614 # etc. These two arguments are required in both cases.
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800615 parser.add_argument(
616 '--sysroot',
617 type='path',
618 metavar='DIR',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800619 help="The root path to the board's build root, e.g. "
620 '/build/eve')
Andrew67b5fa72020-02-05 14:14:48 -0800621 # TODO(andrewlassalle): Remove src-dir in the future(2021?) if nobody uses it.
622 parser.add_argument(
623 '--src-dir',
624 type='path',
625 metavar='SRC_DIR_PATH',
626 help='Override the default Root directory path that contains all DLC '
627 'files to be packed.')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800628 parser.add_argument(
629 '--install-root-dir',
630 type='path',
631 metavar='DIR',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800632 help='If building a specific DLC, it is the root path to'
633 ' install DLC images (%s) and metadata (%s). Otherwise it'
634 ' is the target directory where the Chrome OS images gets'
635 ' dropped in build_image, e.g. '
Andrew67b5fa72020-02-05 14:14:48 -0800636 'src/build/images/<board>/latest.' % (DLC_BUILD_DIR, DLC_META_DIR))
Amin Hassani22a25eb2019-01-11 14:25:02 -0800637
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800638 one_dlc = parser.add_argument_group('Arguments required for building only '
639 'one DLC')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800640 one_dlc.add_argument(
Andrew67b5fa72020-02-05 14:14:48 -0800641 '--rootfs',
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800642 type='path',
Andrew67b5fa72020-02-05 14:14:48 -0800643 metavar='ROOT_FS_PATH',
644 help='Path to the platform rootfs.')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800645 one_dlc.add_argument(
646 '--pre-allocated-blocks',
647 type=int,
648 metavar='PREALLOCATEDBLOCKS',
649 help='Number of blocks (block size is 4k) that need to'
650 'be pre-allocated on device.')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800651 one_dlc.add_argument('--version', metavar='VERSION', help='DLC Version.')
652 one_dlc.add_argument('--id', metavar='ID', help='DLC ID (unique per DLC).')
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800653 one_dlc.add_argument(
654 '--package',
655 metavar='PACKAGE',
656 help='The package ID that is unique within a DLC, One'
657 ' DLC cannot have duplicate package IDs.')
658 one_dlc.add_argument(
659 '--name', metavar='NAME', help='A human-readable name for the DLC.')
660 one_dlc.add_argument(
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700661 '--description',
662 help='The description for the DLC.')
663 one_dlc.add_argument(
Jae Hoon Kimfaca4b02020-01-09 13:49:03 -0800664 '--fs-type',
665 metavar='FS_TYPE',
666 default=_SQUASHFS_TYPE,
667 choices=(_SQUASHFS_TYPE, _EXT4_TYPE),
668 help='File system type of the image.')
669 one_dlc.add_argument(
670 '--preload',
671 default=False,
672 action='store_true',
673 help='Allow preloading of DLC.')
Andrew67b5fa72020-02-05 14:14:48 -0800674 one_dlc.add_argument(
Amin Hassani160e12e2020-04-13 14:29:36 -0700675 '--used-by', default=_USED_BY_SYSTEM,
676 choices=(_USED_BY_USER, _USED_BY_SYSTEM),
677 help='Defines how this DLC will be used so dlcservice can take proper '
678 'actions based on the type of usage. For example, if "user" is passed, '
679 'dlcservice does ref counting when DLC is installed/uninstalled. For '
680 '"system", there will be no such provisions.')
681 one_dlc.add_argument(
Andrew67b5fa72020-02-05 14:14:48 -0800682 '--build-package',
683 default=False,
684 action='store_true',
685 help='Flag to indicate if the script is executed during the '
686 'build_packages phase.')
Xiaochu Liudeed0232018-06-26 10:25:34 -0700687 return parser
688
689
Andrew67b5fa72020-02-05 14:14:48 -0800690def ValidateDlcIdentifier(parser, name):
Amin Hassanibc1a4792019-10-24 14:39:57 -0700691 """Validates the DLC identifiers like ID and package names.
692
693 The name specifications are:
694 - No underscore.
695 - First character should be only alphanumeric.
696 - Other characters can be alphanumeric and '-' (dash).
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800697 - Maximum length of 40 (MAX_ID_NAME) characters.
Amin Hassanibc1a4792019-10-24 14:39:57 -0700698
699 For more info see:
700 https://chromium.googlesource.com/chromiumos/platform2/+/master/dlcservice/docs/developer.md#create-a-dlc-module
701
702 Args:
Andrew67b5fa72020-02-05 14:14:48 -0800703 parser: Arguments parser.
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800704 name: The value of the string to be validated.
Amin Hassanibc1a4792019-10-24 14:39:57 -0700705 """
Jae Hoon Kimdb1cab82020-01-21 19:27:28 -0800706 errors = []
707 if not name:
708 errors.append('Must not be empty.')
709 if not name[0].isalnum():
710 errors.append('Must start with alphanumeric character.')
711 if not re.match(r'^[a-zA-Z0-9][a-zA-Z0-9-]*$', name):
712 errors.append('Must only use alphanumeric and - (dash).')
713 if len(name) > MAX_ID_NAME:
714 errors.append('Must be within %d characters.' % MAX_ID_NAME)
715
716 if errors:
717 msg = '%s is invalid:\n%s' % (name, '\n'.join(errors))
Andrew67b5fa72020-02-05 14:14:48 -0800718 parser.error(msg)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700719
720
Andrew67b5fa72020-02-05 14:14:48 -0800721def ValidateArguments(parser, opts, req_flags, invalid_flags):
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800722 """Validates the correctness of the passed arguments.
723
724 Args:
Andrew67b5fa72020-02-05 14:14:48 -0800725 parser: Arguments parser.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800726 opts: Parsed arguments.
Andrew67b5fa72020-02-05 14:14:48 -0800727 req_flags: all the required flags.
728 invalid_flags: all the flags that are not allowed.
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800729 """
730 # Make sure if the intention is to build one DLC, all the required arguments
Andrew67b5fa72020-02-05 14:14:48 -0800731 # are passed and none of the invalid ones are passed. This will ensure the
732 # script is called twice per DLC.
733 if opts.id:
734 if not all(vars(opts)[x] is not None for x in req_flags):
735 parser.error('If the intention is to build only one DLC, all the flags'
736 '%s required for it should be passed.' % req_flags)
737 if any(vars(opts)[x] is not None for x in invalid_flags):
738 parser.error('If the intention is to build only one DLC, all the flags'
739 '%s should be passed in the build_packages phase, not in '
740 'the build_image phase.' % invalid_flags)
741
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800742 if opts.fs_type == _EXT4_TYPE:
Andrew67b5fa72020-02-05 14:14:48 -0800743 parser.error('ext4 unsupported for DLC, see https://crbug.com/890060')
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800744
Amin Hassanibc1a4792019-10-24 14:39:57 -0700745 if opts.id:
Andrew67b5fa72020-02-05 14:14:48 -0800746 ValidateDlcIdentifier(parser, opts.id)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700747 if opts.package:
Andrew67b5fa72020-02-05 14:14:48 -0800748 ValidateDlcIdentifier(parser, opts.package)
Amin Hassanibc1a4792019-10-24 14:39:57 -0700749
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800750
Xiaochu Liudeed0232018-06-26 10:25:34 -0700751def main(argv):
Andrew67b5fa72020-02-05 14:14:48 -0800752 parser = GetParser()
753 opts = parser.parse_args(argv)
Xiaochu Liudeed0232018-06-26 10:25:34 -0700754 opts.Freeze()
Andrew67b5fa72020-02-05 14:14:48 -0800755 per_dlc_req_args = ['id']
756 per_dlc_invalid_args = []
757 if opts.build_package:
758 per_dlc_req_args += ['pre_allocated_blocks', 'version', 'name',
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700759 'description', 'package', 'install_root_dir']
Andrew67b5fa72020-02-05 14:14:48 -0800760 per_dlc_invalid_args += ['src_dir', 'sysroot']
Amin Hassanib97a5ee2019-01-23 14:44:43 -0800761 else:
Andrew67b5fa72020-02-05 14:14:48 -0800762 per_dlc_req_args += ['sysroot']
763 per_dlc_invalid_args += ['name', 'pre_allocated_blocks', 'version',
764 'package']
765
766 ValidateArguments(parser, opts, per_dlc_req_args, per_dlc_invalid_args)
767
768 if opts.build_package:
769 logging.info('Building package: DLC %s', opts.id)
Jae Hoon Kim6ef63172020-04-06 12:39:04 -0700770 params = EbuildParams(
771 dlc_id=opts.id,
772 dlc_package=opts.package,
773 fs_type=opts.fs_type,
774 name=opts.name,
775 description=opts.description,
776 pre_allocated_blocks=opts.pre_allocated_blocks,
777 version=opts.version,
Amin Hassani160e12e2020-04-13 14:29:36 -0700778 preload=opts.preload,
779 used_by=opts.used_by)
Andrew67b5fa72020-02-05 14:14:48 -0800780 params.StoreDlcParameters(install_root_dir=opts.install_root_dir, sudo=True)
781
782 else:
783 InstallDlcImages(
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800784 sysroot=opts.sysroot,
Andrew67b5fa72020-02-05 14:14:48 -0800785 dlc_id=opts.id,
Jae Hoon Kim5f411e42020-01-09 13:30:56 -0800786 install_root_dir=opts.install_root_dir,
Andrew67b5fa72020-02-05 14:14:48 -0800787 preload=opts.preload,
788 src_dir=opts.src_dir,
789 rootfs=opts.rootfs)