You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
7.7 KiB
262 lines
7.7 KiB
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2021 The ChromiumOS Authors
|
|
# 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."
|
|
"""
|
|
|
|
|
|
__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)
|