From 054e7e5184e74ce5f202e7e4fa4fcee5d4dc8999 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Tue, 6 Apr 2021 17:47:37 -0700 Subject: toolchain-utils: New script to make / on chromebook writable. BUG=None TEST=Tested locally and it succeeded. Change-Id: I8cd548aa6f75ca4db30687d52595fb2a2709a321 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/2809209 Reviewed-by: Manoj Gupta Reviewed-by: Denis Nikitin Commit-Queue: Caroline Tice Tested-by: Caroline Tice Auto-Submit: Caroline Tice --- make_root_writable.py | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100755 make_root_writable.py (limited to 'make_root_writable.py') diff --git a/make_root_writable.py b/make_root_writable.py new file mode 100755 index 00000000..0163adf1 --- /dev/null +++ b/make_root_writable.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright 2021 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Script to make / directory on chromebook writable. + +This script updates a remote chromebook to make the / directory writable." +""" + +from __future__ import print_function + +__author__ = 'cmtice@google.com (Caroline Tice)' + +import argparse +import os +import sys +import time + +from cros_utils import command_executer +from cros_utils import locks +from cros_utils import logger +from cros_utils import machines +from cros_utils import misc + +lock_file = '/tmp/image_chromeos_lock/image_chromeos_lock' + + +def Usage(parser, message): + print('ERROR: %s' % message) + parser.print_help() + sys.exit(0) + + +def RebootChromebook(chromeos_root, remote, cmd_executer): + cmd = 'sudo reboot' + cmd_executer.CrosRunCommand(cmd, chromeos_root=chromeos_root, machine=remote) + time.sleep(10) + success = False + for _ in range(1, 10): + if machines.MachineIsPingable(remote): + success = True + break + time.sleep(1) + return success + + +def ParseOutput(output): + # See comment in FindPartitionNum. + lines = output.split('\n') + num_str = '-1' + for line in lines: + l = line.strip() + words = l.split() + if (len(words) > 2 and words[0] == 'sudo' and + words[1] == '/usr/share/vboot/bin/make_dev_ssd.sh' and + words[-2] == '--partitions'): + num_str = words[-1] + break + num = int(num_str) + + return num + + +def FindPartitionNum(chromeos_root, remote, logs, cmd_executer): + partition_cmd = ('/usr/share/vboot/bin/make_dev_ssd.sh ' + '--remove_rootfs_verification') + _, output, _ = cmd_executer.CrosRunCommandWOutput( + partition_cmd, + chromeos_root=chromeos_root, + machine=remote, + terminated_timeout=10) + + # The command above, with no --partitions flag, should return output + # in the following form: + + # make_dev_ssd.sh: INFO: checking system firmware... + # + # ERROR: YOU ARE TRYING TO MODIFY THE LIVE SYSTEM IMAGE /dev/mmcblk0. + # + # The system may become unusable after that change, especially when you have + # some auto updates in progress. To make it safer, we suggest you to only + # change the partition you have booted with. To do that, re-execute this + # command as: + # + # sudo /usr/share/vboot/bin/make_dev_ssd.sh --partitions 4 + # + # If you are sure to modify other partition, please invoke the command again + # and explicitly assign only one target partition for each time + # (--partitions N ) + # + # make_dev_ssd.sh: ERROR: IMAGE /dev/mmcblk0 IS NOT MODIFIED. + + # We pass this output to the ParseOutput function where it finds the 'sudo' + # line with the partition number and returns the partition number. + + num = ParseOutput(output) + + if num == -1: + logs.LogOutput('Failed to find partition number in "%s"' % output) + return num + + +def TryRemoveRootfsFromPartition(chromeos_root, remote, cmd_executer, + partition_num): + partition_cmd = ('/usr/share/vboot/bin/make_dev_ssd.sh ' + '--remove_rootfs_verification --partition %d' % + partition_num) + ret = cmd_executer.CrosRunCommand( + partition_cmd, + chromeos_root=chromeos_root, + machine=remote, + terminated_timeout=10) + return ret + + +def TryRemountPartitionAsRW(chromeos_root, remote, cmd_executer): + command = 'sudo mount -o remount,rw /' + ret = cmd_executer.CrosRunCommand( + command, + chromeos_root=chromeos_root, + machine=remote, + terminated_timeout=10) + return ret + + +def Main(argv): + parser = argparse.ArgumentParser() + parser.add_argument( + '-c', + '--chromeos_root', + dest='chromeos_root', + help='Target directory for ChromeOS installation.') + parser.add_argument('-r', '--remote', dest='remote', help='Target device.') + parser.add_argument( + '-n', + '--no_lock', + dest='no_lock', + default=False, + action='store_true', + help='Do not attempt to lock remote before imaging. ' + 'This option should only be used in cases where the ' + 'exclusive lock has already been acquired (e.g. in ' + 'a script that calls this one).') + + options = parser.parse_args(argv[1:]) + + # Common initializations + log_level = 'average' + cmd_executer = command_executer.GetCommandExecuter(log_level=log_level) + l = logger.GetLogger() + + if options.chromeos_root is None: + Usage(parser, '--chromeos_root must be set') + + if options.remote is None: + Usage(parser, '--remote must be set') + + options.chromeos_root = os.path.expanduser(options.chromeos_root) + + try: + should_unlock = False + if not options.no_lock: + try: + _ = locks.AcquireLock( + list(options.remote.split()), options.chromeos_root) + should_unlock = True + except Exception as e: + raise RuntimeError('Error acquiring machine: %s' % str(e)) + + # Workaround for crosbug.com/35684. + os.chmod(misc.GetChromeOSKeyFile(options.chromeos_root), 0o600) + + if log_level == 'average': + cmd_executer.SetLogLevel('verbose') + + if not machines.MachineIsPingable(options.remote): + raise RuntimeError('Machine %s does not appear to be up.' % + options.remote) + + ret = TryRemountPartitionAsRW(options.chromeos_root, options.remote, + cmd_executer) + + if ret != 0: + l.LogOutput('Initial mount command failed. Looking for root partition' + ' number.') + part_num = FindPartitionNum(options.chromeos_root, options.remote, l, + cmd_executer) + if part_num != -1: + l.LogOutput('Attempting to remove rootfs verification on partition %d' % + part_num) + ret = TryRemoveRootfsFromPartition(options.chromeos_root, + options.remote, cmd_executer, + part_num) + if ret == 0: + l.LogOutput('Succeeded in removing roofs verification from' + ' partition %d. Rebooting...' % part_num) + if not RebootChromebook(options.chromeos_root, options.remote, + cmd_executer): + raise RuntimeError('Chromebook failed to reboot.') + l.LogOutput('Reboot succeeded. Attempting to remount partition.') + ret = TryRemountPartitionAsRW(options.chromeos_root, options.remote, + cmd_executer) + if ret == 0: + l.LogOutput('Re-mounted / as writable.') + else: + l.LogOutput('Re-mount failed. / is not writable.') + else: + l.LogOutput('Failed to remove rootfs verification from partition' + ' %d.' % part_num) + else: + l.LogOutput('Re-mounted / as writable.') + + l.LogOutput('Exiting.') + + finally: + if should_unlock: + locks.ReleaseLock(list(options.remote.split()), options.chromeos_root) + + return ret + + +if __name__ == '__main__': + retval = Main(sys.argv) + sys.exit(retval) -- cgit v1.2.3