| #!/bin/sh | |
| # | |
| # Copyright 2022 The ChromiumOS Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # | |
| # Install kernel and kernel modules from USB. This script is used by ChromeOS | |
| # kernel developers to recover from bad kernel updates. | |
| # Fail if not running as root. | |
| if [ "$(id -u)" -ne 0 ]; then | |
| echo "chromeos-install-kernel must be run as root" | |
| exit 1 | |
| fi | |
| # Load functions and constants. | |
| # shellcheck source=../../scripts/lib/shflags/shflags | |
| . /usr/share/misc/shflags || exit 1 | |
| # shellcheck source=../chromeos-common-script/share/chromeos-common.sh | |
| . /usr/share/misc/chromeos-common.sh || exit 1 | |
| # shellcheck disable=SC1091 | |
| . /usr/sbin/write_gpt.sh || exit 1 | |
| load_base_vars | |
| DEFINE_boolean clean "${FLAGS_TRUE}" "Remove modules for old kernels" | |
| DEFINE_boolean debug "${FLAGS_FALSE}" "Show debug output" | |
| TMPMNT="$(mktemp -d)" | |
| # Parse the command line. | |
| FLAGS "$@" || exit 1 | |
| eval set -- "${FLAGS_ARGV}" | |
| # Be aggressive in our error checking. shflags functions leak non-zero error | |
| # codes, so this has to be set after we're done parsing flags. | |
| set -eu | |
| remove_rootfs_verification() { | |
| local rootdev="$1" | |
| local partition="$2" | |
| local device | |
| device="$(make_partition_dev "${rootdev}" "${partition}")" | |
| # See remove_rootfs_verification() in make_dev_ssd.sh for how the kernel | |
| # config is modified when rootfs verification is off. | |
| if dump_kernel_config "${device}" | grep -q "root=/dev/dm"; then | |
| /usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification -i \ | |
| "${rootdev}" --partitions "${partition}" | |
| fi | |
| } | |
| cleanup() { | |
| set +eu | |
| if mount | grep -q "${TMPMNT}"; then | |
| umount "${TMPMNT}" | |
| fi | |
| rmdir "${TMPMNT}" | |
| } | |
| main() { | |
| local device | |
| local partition | |
| local rootdev | |
| local usbdev | |
| local version | |
| trap cleanup EXIT | |
| rootdev="$(get_fixed_dst_drive)" | |
| usbdev="$(rootdev -s -d)" | |
| version="$(uname -r)" | |
| if [ "${FLAGS_debug}" = "${FLAGS_TRUE}" ]; then | |
| set -x | |
| fi | |
| if [ "${rootdev}" = "${usbdev}" ]; then | |
| echo "Error: target and destination are the same: ${rootdev}" | |
| exit 1 | |
| fi | |
| # Rootfs verification needs to be removed from the rootdev partitions so that | |
| # we can mount them and push new modules. We remove it from the usbdev so | |
| # when we copy that kernel to rootdev it will boot successfully. | |
| remove_rootfs_verification "${rootdev}" "${PARTITION_NUM_KERN_A:?}" | |
| remove_rootfs_verification "${rootdev}" "${PARTITION_NUM_KERN_B:?}" | |
| remove_rootfs_verification "${usbdev}" "${PARTITION_NUM_KERN_A:?}" | |
| for partition in "${PARTITION_NUM_ROOT_A:?}" "${PARTITION_NUM_ROOT_B:?}"; do | |
| device="$(make_partition_dev "${rootdev}" "${partition}")" | |
| mount "${device}" "${TMPMNT}" | |
| if [ "${FLAGS_clean}" = "${FLAGS_TRUE}" ]; then | |
| rm -rf "${TMPMNT}"/lib/modules/* | |
| else | |
| rm -rf "${TMPMNT}"/lib/modules/"${version}" | |
| fi | |
| cp -a /lib/modules/"${version}" "${TMPMNT}"/lib/modules/ | |
| umount "${TMPMNT}" | |
| done | |
| device="$(make_partition_dev "${usbdev}" "${PARTITION_NUM_KERN_A}")" | |
| for partition in "${PARTITION_NUM_KERN_A}" "${PARTITION_NUM_KERN_B}"; do | |
| local target_device | |
| target_device="$(make_partition_dev "${rootdev}" "${partition}")" | |
| dd if="${device}" of="${target_device}" bs=4M | |
| done | |
| sync | |
| cleanup | |
| trap - EXIT | |
| echo "------------------------------------------------------------" | |
| echo "Installation to '${rootdev}' complete." | |
| } | |
| main "$@" |