blob: 6d041d07f2d9ed06ba21f64628bbba389ca0801e [file] [log] [blame]
David Pursellf1d16a62015-03-25 13:31:04 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Install/copy the image to the device."""
6
7from __future__ import print_function
8
David Pursellf1d16a62015-03-25 13:31:04 -07009import os
Ralph Nathan9b997232015-05-15 13:13:12 -070010import re
David Pursellf1d16a62015-03-25 13:31:04 -070011import shutil
12import tempfile
David Pursellf1d16a62015-03-25 13:31:04 -070013
14from chromite.cbuildbot import constants
xixuane851dfb2016-05-02 18:02:37 -070015from chromite.lib import auto_updater
David Pursellf1d16a62015-03-25 13:31:04 -070016from chromite.lib import commandline
17from chromite.lib import cros_build_lib
18from chromite.lib import cros_logging as logging
19from chromite.lib import dev_server_wrapper as ds_wrapper
Ralph Nathan872ea4d2015-05-05 18:04:56 -070020from chromite.lib import operation
David Pursellf1d16a62015-03-25 13:31:04 -070021from chromite.lib import osutils
Gilad Arnold1c8eda52015-05-04 22:32:38 -070022from chromite.lib import path_util
David Pursellf1d16a62015-03-25 13:31:04 -070023from chromite.lib import remote_access
24
25
Don Garrett97d7dc22015-01-20 14:07:56 -080026DEVSERVER_STATIC_DIR = path_util.FromChrootPath(
David Pursellf1d16a62015-03-25 13:31:04 -070027 os.path.join(constants.CHROOT_SOURCE_ROOT, 'devserver', 'static'))
28
29
Ralph Nathan9b997232015-05-15 13:13:12 -070030class UsbImagerOperation(operation.ProgressBarOperation):
31 """Progress bar for flashing image to operation."""
32
33 def __init__(self, image):
34 super(UsbImagerOperation, self).__init__()
35 self._size = os.path.getsize(image)
36 self._transferred = 0.
37 self._bytes = re.compile(r'(\d+) bytes')
38
39 def _GetDDPid(self):
40 """Get the Pid of dd."""
41 try:
42 pids = cros_build_lib.RunCommand(['pgrep', 'dd'], capture_output=True,
43 print_cmd=False).output
44 for pid in pids.splitlines():
45 if osutils.IsChildProcess(int(pid), name='dd'):
46 return int(pid)
47 return -1
48 except cros_build_lib.RunCommandError:
49 # If dd isn't still running, then we assume that it is finished.
50 return -1
51
52 def _PingDD(self, dd_pid):
53 """Send USR1 signal to dd to get status update."""
54 try:
55 cmd = ['kill', '-USR1', str(dd_pid)]
56 cros_build_lib.SudoRunCommand(cmd, print_cmd=False)
57 except cros_build_lib.RunCommandError:
58 # Here we assume that dd finished in the background.
59 return
60
61 def ParseOutput(self, output=None):
62 """Parse the output of dd to update progress bar."""
63 dd_pid = self._GetDDPid()
64 if dd_pid == -1:
65 return
66
67 self._PingDD(dd_pid)
68
69 if output is None:
70 stdout = self._stdout.read()
71 stderr = self._stderr.read()
72 output = stdout + stderr
73
74 match = self._bytes.search(output)
75 if match:
76 self._transferred = match.groups()[0]
77
78 self.ProgressBar(float(self._transferred) / self._size)
79
80
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070081def _IsFilePathGPTDiskImage(file_path):
82 """Determines if a file is a valid GPT disk.
83
84 Args:
85 file_path: Path to the file to test.
86 """
87 if os.path.isfile(file_path):
88 with cros_build_lib.Open(file_path) as image_file:
89 image_file.seek(0x1fe)
90 if image_file.read(10) == '\x55\xaaEFI PART':
91 return True
92 return False
93
94
95def _ChooseImageFromDirectory(dir_path):
96 """Lists all image files in |dir_path| and ask user to select one.
97
98 Args:
99 dir_path: Path to the directory.
100 """
101 images = sorted([x for x in os.listdir(dir_path) if
102 _IsFilePathGPTDiskImage(os.path.join(dir_path, x))])
103 idx = 0
104 if len(images) == 0:
105 raise ValueError('No image found in %s.' % dir_path)
106 elif len(images) > 1:
107 idx = cros_build_lib.GetChoice(
108 'Multiple images found in %s. Please select one to continue:' % (
109 (dir_path,)),
110 images)
111
112 return os.path.join(dir_path, images[idx])
113
114
David Pursellf1d16a62015-03-25 13:31:04 -0700115class FlashError(Exception):
116 """Thrown when there is an unrecoverable error during flash."""
117
118
119class USBImager(object):
120 """Copy image to the target removable device."""
121
Gilad Arnoldd0461442015-07-07 11:52:46 -0700122 def __init__(self, device, board, image, debug=False, install=False,
123 yes=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700124 """Initalizes USBImager."""
125 self.device = device
126 self.board = board if board else cros_build_lib.GetDefaultBoard()
127 self.image = image
David Pursellf1d16a62015-03-25 13:31:04 -0700128 self.debug = debug
129 self.debug_level = logging.DEBUG if debug else logging.INFO
130 self.install = install
131 self.yes = yes
132
133 def DeviceNameToPath(self, device_name):
134 return '/dev/%s' % device_name
135
136 def GetRemovableDeviceDescription(self, device):
137 """Returns a informational description of the removable |device|.
138
139 Args:
140 device: the device name (e.g. sdc).
141
142 Returns:
143 A string describing |device| (e.g. Patriot Memory 7918 MB).
144 """
145 desc = [
146 osutils.GetDeviceInfo(device, keyword='manufacturer'),
147 osutils.GetDeviceInfo(device, keyword='product'),
148 osutils.GetDeviceSize(self.DeviceNameToPath(device)),
149 '(%s)' % self.DeviceNameToPath(device),
150 ]
151 return ' '.join([x for x in desc if x])
152
153 def ListAllRemovableDevices(self):
154 """Returns a list of removable devices.
155
156 Returns:
157 A list of device names (e.g. ['sdb', 'sdc']).
158 """
159 devices = osutils.ListBlockDevices()
160 removable_devices = []
161 for d in devices:
162 if d.TYPE == 'disk' and d.RM == '1':
163 removable_devices.append(d.NAME)
164
165 return removable_devices
166
167 def ChooseRemovableDevice(self, devices):
168 """Lists all removable devices and asks user to select/confirm.
169
170 Args:
171 devices: a list of device names (e.g. ['sda', 'sdb']).
172
173 Returns:
174 The device name chosen by the user.
175 """
176 idx = cros_build_lib.GetChoice(
177 'Removable device(s) found. Please select/confirm to continue:',
178 [self.GetRemovableDeviceDescription(x) for x in devices])
179
180 return devices[idx]
181
182 def InstallImageToDevice(self, image, device):
183 """Installs |image| to the removable |device|.
184
185 Args:
186 image: Path to the image to copy.
187 device: Device to copy to.
188 """
189 cmd = [
190 'chromeos-install',
191 '--yes',
192 '--skip_src_removable',
193 '--skip_dst_removable',
194 '--payload_image=%s' % image,
195 '--dst=%s' % device,
196 '--skip_postinstall',
197 ]
198 cros_build_lib.SudoRunCommand(cmd)
199
200 def CopyImageToDevice(self, image, device):
201 """Copies |image| to the removable |device|.
202
203 Args:
204 image: Path to the image to copy.
205 device: Device to copy to.
206 """
Ralph Nathan9b997232015-05-15 13:13:12 -0700207 cmd = ['dd', 'if=%s' % image, 'of=%s' % device, 'bs=4M', 'iflag=fullblock',
208 'oflag=sync']
209 if logging.getLogger().getEffectiveLevel() <= logging.NOTICE:
210 op = UsbImagerOperation(image)
211 op.Run(cros_build_lib.SudoRunCommand, cmd, debug_level=logging.NOTICE,
212 update_period=0.5)
213 else:
214 cros_build_lib.SudoRunCommand(
215 cmd, debug_level=logging.NOTICE,
216 print_cmd=logging.getLogger().getEffectiveLevel() < logging.NOTICE)
David Pursellf1d16a62015-03-25 13:31:04 -0700217
David Pursellf1d16a62015-03-25 13:31:04 -0700218 cros_build_lib.SudoRunCommand(['sync'], debug_level=self.debug_level)
219
David Pursellf1d16a62015-03-25 13:31:04 -0700220 def _GetImagePath(self):
221 """Returns the image path to use."""
222 image_path = translated_path = None
223 if os.path.isfile(self.image):
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700224 if not self.yes and not _IsFilePathGPTDiskImage(self.image):
David Pursellf1d16a62015-03-25 13:31:04 -0700225 # TODO(wnwen): Open the tarball and if there is just one file in it,
226 # use that instead. Existing code in upload_symbols.py.
227 if cros_build_lib.BooleanPrompt(
228 prolog='The given image file is not a valid disk image. Perhaps '
229 'you forgot to untar it.',
230 prompt='Terminate the current flash process?'):
231 raise FlashError('Update terminated by user.')
232 image_path = self.image
233 elif os.path.isdir(self.image):
234 # Ask user which image (*.bin) in the folder to use.
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700235 image_path = _ChooseImageFromDirectory(self.image)
David Pursellf1d16a62015-03-25 13:31:04 -0700236 else:
237 # Translate the xbuddy path to get the exact image to use.
Gilad Arnolde62ec902015-04-24 14:41:02 -0700238 translated_path, _ = ds_wrapper.GetImagePathWithXbuddy(
Don Garrett97d7dc22015-01-20 14:07:56 -0800239 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700240 image_path = ds_wrapper.TranslatedPathToLocalPath(
Don Garrett97d7dc22015-01-20 14:07:56 -0800241 translated_path, DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700242
243 logging.info('Using image %s', translated_path or image_path)
244 return image_path
245
246 def Run(self):
247 """Image the removable device."""
248 devices = self.ListAllRemovableDevices()
249
250 if self.device:
251 # If user specified a device path, check if it exists.
252 if not os.path.exists(self.device):
253 raise FlashError('Device path %s does not exist.' % self.device)
254
255 # Then check if it is removable.
256 if self.device not in [self.DeviceNameToPath(x) for x in devices]:
257 msg = '%s is not a removable device.' % self.device
258 if not (self.yes or cros_build_lib.BooleanPrompt(
259 default=False, prolog=msg)):
260 raise FlashError('You can specify usb:// to choose from a list of '
261 'removable devices.')
262 target = None
263 if self.device:
264 # Get device name from path (e.g. sdc in /dev/sdc).
265 target = self.device.rsplit(os.path.sep, 1)[-1]
266 elif devices:
267 # Ask user to choose from the list.
268 target = self.ChooseRemovableDevice(devices)
269 else:
270 raise FlashError('No removable devices detected.')
271
272 image_path = self._GetImagePath()
273 try:
274 device = self.DeviceNameToPath(target)
275 if self.install:
276 self.InstallImageToDevice(image_path, device)
277 else:
278 self.CopyImageToDevice(image_path, device)
279 except cros_build_lib.RunCommandError:
280 logging.error('Failed copying image to device %s',
281 self.DeviceNameToPath(target))
282
283
284class FileImager(USBImager):
285 """Copy image to the target path."""
286
287 def Run(self):
288 """Copy the image to the path specified by self.device."""
Mao Huangc4777e82016-03-14 20:20:08 +0800289 if not os.path.isdir(os.path.dirname(self.device)):
290 raise FlashError('Parent of path %s is not a directory.' % self.device)
David Pursellf1d16a62015-03-25 13:31:04 -0700291
292 image_path = self._GetImagePath()
293 if os.path.isdir(self.device):
294 logging.info('Copying to %s',
295 os.path.join(self.device, os.path.basename(image_path)))
296 else:
297 logging.info('Copying to %s', self.device)
298 try:
299 shutil.copy(image_path, self.device)
300 except IOError:
301 logging.error('Failed to copy image %s to %s', image_path, self.device)
302
303
304class RemoteDeviceUpdater(object):
305 """Performs update on a remote device."""
306 DEVSERVER_FILENAME = 'devserver.py'
307 STATEFUL_UPDATE_BIN = '/usr/bin/stateful_update'
308 UPDATE_ENGINE_BIN = 'update_engine_client'
David Pursellf1d16a62015-03-25 13:31:04 -0700309 # Root working directory on the device. This directory is in the
310 # stateful partition and thus has enough space to store the payloads.
311 DEVICE_BASE_DIR = '/mnt/stateful_partition/cros-flash'
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700312 UPDATE_CHECK_INTERVAL_PROGRESSBAR = 0.5
313 UPDATE_CHECK_INTERVAL_NORMAL = 10
David Pursellf1d16a62015-03-25 13:31:04 -0700314
315 def __init__(self, ssh_hostname, ssh_port, image, stateful_update=True,
316 rootfs_update=True, clobber_stateful=False, reboot=True,
Gilad Arnoldd0461442015-07-07 11:52:46 -0700317 board=None, src_image_to_delta=None, wipe=True, debug=False,
318 yes=False, force=False, ping=True,
Gilad Arnold821547c2015-07-07 08:57:48 -0700319 disable_verification=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700320 """Initializes RemoteDeviceUpdater"""
321 if not stateful_update and not rootfs_update:
322 raise ValueError('No update operation to perform; either stateful or'
323 ' rootfs partitions must be updated.')
324 self.tempdir = tempfile.mkdtemp(prefix='cros-flash')
325 self.ssh_hostname = ssh_hostname
326 self.ssh_port = ssh_port
327 self.image = image
328 self.board = board
David Pursellf1d16a62015-03-25 13:31:04 -0700329 self.src_image_to_delta = src_image_to_delta
330 self.do_stateful_update = stateful_update
331 self.do_rootfs_update = rootfs_update
332 self.disable_verification = disable_verification
333 self.clobber_stateful = clobber_stateful
334 self.reboot = reboot
335 self.debug = debug
336 self.ping = ping
337 # Do not wipe if debug is set.
338 self.wipe = wipe and not debug
339 self.yes = yes
340 self.force = force
David Pursellf1d16a62015-03-25 13:31:04 -0700341
David Pursellf1d16a62015-03-25 13:31:04 -0700342 def Cleanup(self):
343 """Cleans up the temporary directory."""
344 if self.wipe:
345 logging.info('Cleaning up temporary working directory...')
346 osutils.RmDir(self.tempdir)
347 else:
348 logging.info('You can find the log files and/or payloads in %s',
349 self.tempdir)
350
xixuane851dfb2016-05-02 18:02:37 -0700351 def GetPayloadDir(self, device):
352 """Get directory of payload for update.
David Pursellf1d16a62015-03-25 13:31:04 -0700353
xixuane851dfb2016-05-02 18:02:37 -0700354 This method is used to obtain the directory of payload for cros-flash. The
355 given path 'self.image' is passed in when initializing RemoteDeviceUpdater.
David Pursellf1d16a62015-03-25 13:31:04 -0700356
xixuane851dfb2016-05-02 18:02:37 -0700357 If self.image is a directory, we directly use the provided update payload(s)
358 in this directory.
359
360 If self.image is an image, let devserver access it and generate payloads.
361
362 If not in the above cases, let devserver first obtain the image path. Then
363 devserver will access the image and generate payloads.
David Pursellf1d16a62015-03-25 13:31:04 -0700364
365 Args:
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400366 device: A ChromiumOSDevice object.
David Pursellf1d16a62015-03-25 13:31:04 -0700367
368 Returns:
xixuane851dfb2016-05-02 18:02:37 -0700369 A string payload_dir, that represents the payload directory.
David Pursellf1d16a62015-03-25 13:31:04 -0700370 """
xixuane851dfb2016-05-02 18:02:37 -0700371 payload_dir = self.tempdir
David Pursellf1d16a62015-03-25 13:31:04 -0700372
xixuane851dfb2016-05-02 18:02:37 -0700373 if os.path.isdir(self.image):
374 # The given path is a directory.
375 payload_dir = self.image
376 logging.info('Using provided payloads in %s', payload_dir)
377 elif os.path.isfile(self.image):
378 # The given path is an image.
379 logging.info('Using image %s', self.image)
380 ds_wrapper.GetUpdatePayloadsFromLocalPath(
381 self.image, payload_dir,
382 src_image_to_delta=self.src_image_to_delta,
383 static_dir=DEVSERVER_STATIC_DIR)
384 else:
385 self.board = cros_build_lib.GetBoard(device_board=device.board,
386 override_board=self.board,
387 force=self.yes)
388 if not self.board:
389 raise FlashError('No board identified')
David Pursellf1d16a62015-03-25 13:31:04 -0700390
xixuane851dfb2016-05-02 18:02:37 -0700391 if not self.force and self.board != device.board:
392 # If a board was specified, it must be compatible with the device.
Brian Norrisfab3fb22016-06-02 14:59:20 -0700393 raise FlashError('Device (%s) is incompatible with board %s' %
394 (device.board, self.board))
xixuane851dfb2016-05-02 18:02:37 -0700395
396 logging.info('Board is %s', self.board)
397
398 # Translate the xbuddy path to get the exact image to use.
399 translated_path, resolved_path = ds_wrapper.GetImagePathWithXbuddy(
400 self.image, self.board, static_dir=DEVSERVER_STATIC_DIR,
401 lookup_only=True)
402 logging.info('Using image %s', translated_path)
403 # Convert the translated path to be used in the update request.
404 image_path = ds_wrapper.ConvertTranslatedPath(resolved_path,
405 translated_path)
406
407 # Launch a local devserver to generate/serve update payloads.
408 ds_wrapper.GetUpdatePayloads(
409 image_path, payload_dir, board=self.board,
410 src_image_to_delta=self.src_image_to_delta,
411 static_dir=DEVSERVER_STATIC_DIR)
412
413 return payload_dir
David Pursellf1d16a62015-03-25 13:31:04 -0700414
415 def Run(self):
xixuane851dfb2016-05-02 18:02:37 -0700416 """Perform remote device update.
417
418 The update process includes:
419 1. initialize a device instance for the given remote device.
420 2. achieve payload_dir which contains the required payloads for updating.
421 3. initialize an auto-updater instance to do RunUpdate().
422 4. After auto-update, all temp files and dir will be cleaned up.
423 """
David Pursellf1d16a62015-03-25 13:31:04 -0700424 try:
425 device_connected = False
xixuane851dfb2016-05-02 18:02:37 -0700426
David Pursellf1d16a62015-03-25 13:31:04 -0700427 with remote_access.ChromiumOSDeviceHandler(
428 self.ssh_hostname, port=self.ssh_port,
429 base_dir=self.DEVICE_BASE_DIR, ping=self.ping) as device:
430 device_connected = True
431
xixuane851dfb2016-05-02 18:02:37 -0700432 # Get payload directory
433 payload_dir = self.GetPayloadDir(device)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700434
xixuane851dfb2016-05-02 18:02:37 -0700435 # Do auto-update
436 chromeos_AU = auto_updater.ChromiumOSUpdater(
437 device, payload_dir, self.tempdir,
438 do_rootfs_update=self.do_rootfs_update,
439 do_stateful_update=self.do_stateful_update,
440 reboot=self.reboot,
441 disable_verification=self.disable_verification,
442 clobber_stateful=self.clobber_stateful,
443 yes=self.yes)
444 chromeos_AU.CheckPayloads()
445 chromeos_AU.RunUpdate()
David Pursellf1d16a62015-03-25 13:31:04 -0700446
447 except Exception:
448 logging.error('Device update failed.')
449 if device_connected and device.lsb_release:
450 lsb_entries = sorted(device.lsb_release.items())
451 logging.info('Following are the LSB version details of the device:\n%s',
452 '\n'.join('%s=%s' % (k, v) for k, v in lsb_entries))
453 raise
454 else:
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700455 logging.notice('Update performed successfully.')
David Pursellf1d16a62015-03-25 13:31:04 -0700456 finally:
457 self.Cleanup()
458
Gilad Arnoldbfcfaff2015-07-07 10:08:02 -0700459def Flash(device, image, board=None, install=False, src_image_to_delta=None,
460 rootfs_update=True, stateful_update=True, clobber_stateful=False,
461 reboot=True, wipe=True, ping=True, disable_rootfs_verification=False,
462 clear_cache=False, yes=False, force=False, debug=False):
David Pursellf1d16a62015-03-25 13:31:04 -0700463 """Flashes a device, USB drive, or file with an image.
464
465 This provides functionality common to `cros flash` and `brillo flash`
466 so that they can parse the commandline separately but still use the
467 same underlying functionality.
468
469 Args:
David Pursell2e773382015-04-03 14:30:47 -0700470 device: commandline.Device object; None to use the default device.
David Pursellf1d16a62015-03-25 13:31:04 -0700471 image: Path (string) to the update image. Can be a local or xbuddy path;
472 non-existant local paths are converted to xbuddy.
David Pursellf1d16a62015-03-25 13:31:04 -0700473 board: Board to use; None to automatically detect.
David Pursellf1d16a62015-03-25 13:31:04 -0700474 install: Install to USB using base disk layout; USB |device| scheme only.
475 src_image_to_delta: Local path to an image to be used as the base to
476 generate delta payloads; SSH |device| scheme only.
477 rootfs_update: Update rootfs partition; SSH |device| scheme only.
478 stateful_update: Update stateful partition; SSH |device| scheme only.
479 clobber_stateful: Clobber stateful partition; SSH |device| scheme only.
480 reboot: Reboot device after update; SSH |device| scheme only.
481 wipe: Wipe temporary working directory; SSH |device| scheme only.
482 ping: Ping the device before attempting update; SSH |device| scheme only.
483 disable_rootfs_verification: Remove rootfs verification after update; SSH
484 |device| scheme only.
485 clear_cache: Clear the devserver static directory.
486 yes: Assume "yes" for any prompt.
487 force: Ignore sanity checks and prompts. Overrides |yes| if True.
488 debug: Print additional debugging messages.
489
490 Raises:
491 FlashError: An unrecoverable error occured.
492 ValueError: Invalid parameter combination.
493 """
494 if force:
495 yes = True
496
497 if clear_cache:
498 logging.info('Clearing the cache...')
Don Garrett97d7dc22015-01-20 14:07:56 -0800499 ds_wrapper.DevServerWrapper.WipeStaticDirectory(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700500
501 try:
Don Garrett97d7dc22015-01-20 14:07:56 -0800502 osutils.SafeMakedirsNonRoot(DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700503 except OSError:
Don Garrett97d7dc22015-01-20 14:07:56 -0800504 logging.error('Failed to create %s', DEVSERVER_STATIC_DIR)
David Pursellf1d16a62015-03-25 13:31:04 -0700505
506 if install:
David Pursell2e773382015-04-03 14:30:47 -0700507 if not device or device.scheme != commandline.DEVICE_SCHEME_USB:
David Pursellf1d16a62015-03-25 13:31:04 -0700508 raise ValueError(
509 '--install can only be used when writing to a USB device')
510 if not cros_build_lib.IsInsideChroot():
511 raise ValueError('--install can only be used inside the chroot')
512
David Pursell2e773382015-04-03 14:30:47 -0700513 if not device or device.scheme == commandline.DEVICE_SCHEME_SSH:
514 if device:
515 hostname, port = device.hostname, device.port
516 else:
517 hostname, port = None, None
Ralph Nathan872ea4d2015-05-05 18:04:56 -0700518 logging.notice('Preparing to update the remote device %s', hostname)
David Pursellf1d16a62015-03-25 13:31:04 -0700519 updater = RemoteDeviceUpdater(
David Pursell2e773382015-04-03 14:30:47 -0700520 hostname,
521 port,
David Pursellf1d16a62015-03-25 13:31:04 -0700522 image,
523 board=board,
David Pursellf1d16a62015-03-25 13:31:04 -0700524 src_image_to_delta=src_image_to_delta,
525 rootfs_update=rootfs_update,
526 stateful_update=stateful_update,
527 clobber_stateful=clobber_stateful,
528 reboot=reboot,
529 wipe=wipe,
530 debug=debug,
531 yes=yes,
532 force=force,
533 ping=ping,
Gilad Arnold821547c2015-07-07 08:57:48 -0700534 disable_verification=disable_rootfs_verification)
David Pursellf1d16a62015-03-25 13:31:04 -0700535 updater.Run()
536 elif device.scheme == commandline.DEVICE_SCHEME_USB:
537 path = osutils.ExpandPath(device.path) if device.path else ''
538 logging.info('Preparing to image the removable device %s', path)
539 imager = USBImager(path,
540 board,
541 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700542 debug=debug,
543 install=install,
544 yes=yes)
545 imager.Run()
546 elif device.scheme == commandline.DEVICE_SCHEME_FILE:
547 logging.info('Preparing to copy image to %s', device.path)
548 imager = FileImager(device.path,
549 board,
550 image,
David Pursellf1d16a62015-03-25 13:31:04 -0700551 debug=debug,
552 yes=yes)
553 imager.Run()