From 8cd88bfe3b4df1ec54cefe4bd2f15ce7ae073674 Mon Sep 17 00:00:00 2001 From: SteveChen Date: Sun, 6 May 2018 15:15:54 +0800 Subject: [PATCH] i2SOM:recovery: add initram system file for recovery --- .../recovery/recovery-initramfs.bb | 40 ++ .../recovery-initramfs/automount_block.sh | 63 +++ .../recovery-initramfs/automount_mtd.sh | 52 +++ .../recovery/recovery-initramfs/mdev.conf | 4 + .../recovery-initramfs-init | 389 ++++++++++++++++++ .../recovery/recovery-initramfs/swupdate.cfg | 7 + 6 files changed, 555 insertions(+) create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs.bb create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_block.sh create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_mtd.sh create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/mdev.conf create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init create mode 100644 meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/swupdate.cfg diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs.bb b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs.bb new file mode 100644 index 0000000..92a1c1a --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs.bb @@ -0,0 +1,40 @@ +# +# Copyright (C) 2017 i2SOM Team. +# + +SUMMARY = "Recovery system files" +LICENSE = "GPL-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" + +SRC_URI = " \ + file://recovery-initramfs-init \ + file://swupdate.cfg \ + file://automount_block.sh \ + file://automount_mtd.sh \ + file://mdev.conf \ +" + +S = "${WORKDIR}" + +do_install() { + install -d ${D}${sysconfdir} + install -d ${D}${base_sbindir} + install -m 0755 ${WORKDIR}/recovery-initramfs-init ${D}${base_sbindir}/init + install -m 0644 ${WORKDIR}/swupdate.cfg ${D}${sysconfdir} + install -d ${D}${base_libdir}/mdev + install -m 0755 ${WORKDIR}/automount_block.sh ${D}${base_libdir}/mdev/automount_block.sh + install -m 0755 ${WORKDIR}/automount_mtd.sh ${D}${base_libdir}/mdev/automount_mtd.sh + install -m 0644 ${WORKDIR}/mdev.conf ${D}${sysconfdir} + + rm -rf ${D}${localstatedir}/lock +} + +# Do not create debug/devel packages +PACKAGES = "${PN}" + +FILES_${PN} = "/ " + +RDEPENDS_${PN}_append_i2c6ulxbn = " \ + cryptsetup \ + rng-tools \ +" diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_block.sh b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_block.sh new file mode 100644 index 0000000..70750f6 --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_block.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# +# Copyright (c) 2017 i2SOM Team. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at http://mozilla.org/MPL/2.0/. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +MDEV_AUTOMOUNT_ROOT="/run/media" +UPDATE_MOUNTPOINT="/mnt/update" + +DEVICE="$(echo "${MDEV}" | sed -n -e '/^mmc/{s,^\([^p]\+\)p[0-9]\+$,\1,g;T;p}' -e '/^sd/{s,^\([^0-9]\+\)[0-9]\+$,\1,g;T;p}')" +PARTITION="$(echo "${MDEV}" | sed -n -e '/^mmc/{s,^[^p]\+p\([0-9]\+\)$,\1,g;T;p}' -e '/^sd/{s,^[^0-9]\+\([0-9]\+\)$,\1,g;T;p}')" + +# This will detect if the block device has a update partition +is_update_device() { + parted -s "/dev/${DEVICE}" print | grep -qs update +} + +# This will verify that the requested partition is the update partition +is_update_partition() { + parted -s "/dev/${DEVICE}" print | sed -ne "s,^[^0-9]*\([0-9]\+\).*\.*,\1,g;T;p" | grep -qs "${PARTITION}" +} + +if is_update_device; then + if is_update_partition; then + if mkdir -p ${UPDATE_MOUNTPOINT} && ! mountpoint -q ${UPDATE_MOUNTPOINT}; then + FSTYPE="$(blkid /dev/${MDEV} | sed -e 's,.*TYPE="\([^"]\+\)".*,\1,g')" + if ! mount ${FSTYPE:+-t ${FSTYPE}} "/dev/${MDEV}" "${UPDATE_MOUNTPOINT}"; then + rmdir --ignore-fail-on-non-empty ${UPDATE_MOUNTPOINT} + fi + fi + fi + # If it's 'update' device but not partition, just exit + exit 0 +fi + +case "${ACTION}" in +add) + # Create mountpoint and mount the mmc device + if mkdir -p ${MDEV_AUTOMOUNT_ROOT}/${MDEV} && ! mountpoint -q ${MDEV_AUTOMOUNT_ROOT}/${MDEV}; then + FSTYPE="$(blkid /dev/${MDEV} | sed -e 's,.*TYPE="\([^"]\+\)".*,\1,g')" + mount -r ${FSTYPE:+-t ${FSTYPE}} /dev/${MDEV} ${MDEV_AUTOMOUNT_ROOT}/${MDEV} + fi + ;; +remove) + # Umount and then remove mountpoint + if grep -q "/dev/${MDEV}[[:blank:]]" /proc/mounts; then + mdir=$(sed -ne "s,/dev/${MDEV}[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]].*,\1,g;T;p" /proc/mounts) + umount "${mdir}" + rmdir -- "${mdir}" 2>/dev/null + fi + ;; +esac diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_mtd.sh b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_mtd.sh new file mode 100644 index 0000000..ea8c907 --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/automount_mtd.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# Copyright (c) 2017 i2SOM Team. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at http://mozilla.org/MPL/2.0/. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +UPDATE_MOUNTPOINT="/mnt/update" +PARTITION_NAME="update" + +# This will detect if the block device has a update partition +is_update_device() { + grep -qs update /proc/mtd +} + +# This will verify that the requested partition is the update partition +is_update_partition() { + grep -qs "^${MDEV}:.*\.*" /proc/mtd +} + +if is_update_device; then + if is_update_partition; then + # Attach and get UBI device number + dev_number="$(ubiattach -p /dev/${MDEV} 2>/dev/null | sed -ne 's,.*device number \([0-9]\).*,\1,g;T;p' 2>/dev/null)" + # Check if volume exists. + if ubinfo "/dev/ubi${dev_number}" -N "${PARTITION_NAME}" >/dev/null 2>&1; then + if mkdir -p ${UPDATE_MOUNTPOINT} && ! mountpoint -q ${UPDATE_MOUNTPOINT}; then + # Mount the volume. + if ! mount -t ubifs "ubi${dev_number}:${PARTITION_NAME}" "${UPDATE_MOUNTPOINT}"; then + echo "ERROR: Could not mount '${PARTITION_NAME}' partition" + rmdir --ignore-fail-on-non-empty ${UPDATE_MOUNTPOINT} + fi + fi + else + echo "ERROR: Could not mount '${PARTITION_NAME}' partition, volume not found" + ubidetach -p "/dev/${MDEV}" >/dev/null 2>&1 + rmdir --ignore-fail-on-non-empty ${UPDATE_MOUNTPOINT} + fi + fi + # If it's 'update' device but not partition, just exit + exit 0 +fi diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/mdev.conf b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/mdev.conf new file mode 100644 index 0000000..6579cf3 --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/mdev.conf @@ -0,0 +1,4 @@ +# block devices +sd[a-z][0-9]+ 0:0 660 */lib/mdev/automount_block.sh +mmcblk[0]+p[0-9]+ 0:0 660 */lib/mdev/automount_block.sh +mtd[0-9]+ 0:0 660 */lib/mdev/automount_mtd.sh diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init new file mode 100644 index 0000000..35afa7d --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init @@ -0,0 +1,389 @@ +#!/bin/sh +#=============================================================================== +# +# recovery-initramfs-init +# +# Copyright (C) 2017 i2SOM Team. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published by +# the Free Software Foundation. +# +# +# Description: Init script for recovery initramfs +# +#=============================================================================== + +# Variables. +#------------------------------------------------------------------------------ +ENV_BOOT_RECOVERY="boot_recovery" +ENV_RECOVERY_COMMAND="recovery_command" + +PUBLIC_KEY="/etc/ssl/certs/key.pub" + +USB_MOUNT_DIR="/run/media" +UPDATE_MOUNT_DIR="/mnt/update" + +REBOOT_TIME=10 + +# Functions. +#------------------------------------------------------------------------------ +#------------------------------------------------------------------------------ +# Function - log +# +# Prints the given text in the console. +# +# @param ${1} - Text to print. +#------------------------------------------------------------------------------ +log() { + echo "[RECOVERY] ${1}" 1>&2 +} + +#------------------------------------------------------------------------------ +# Function - log_warning +# +# Prints the given text in the console as a warning. +# +# @param ${1} - Warning text to print. +#------------------------------------------------------------------------------ +log_warning() { + log "[WARNING] ${1}" +} + +#------------------------------------------------------------------------------ +# Function - log_error +# +# Prints the given text in the console as an error. +# +# @param ${1} - Error text to print. +#------------------------------------------------------------------------------ +log_error() { + log "[ERROR] ${1}" + psplash_message "ERROR: ${1}" + psplash_progress "0" +} + +#------------------------------------------------------------------------------ +# Function - clear_uboot_vars +# +# Clears recovery U-Boot variables. +#------------------------------------------------------------------------------ +clear_uboot_vars() { + fw_setenv "${ENV_BOOT_RECOVERY}" + fw_setenv "${ENV_RECOVERY_COMMAND}" +} + +#------------------------------------------------------------------------------ +# Function - read_uboot_var +# +# Reads the given U-Boot variable. +# +# @param ${1} - U-Boot variable to read. +# @param ${2} - Where to store the value of the read variable. +#------------------------------------------------------------------------------ +read_uboot_var() { + eval "${2}=\"$(fw_printenv -n ${1} 2>/dev/null)\"" +} + +#------------------------------------------------------------------------------ +# Function - set_uboot_var +# +# Sets the given U-Boot variable. +# +# @param ${1} - U-Boot variable to set. +# @param ${2} - Value to set. +#------------------------------------------------------------------------------ +set_uboot_var() { + fw_setenv ${1} ${2} 2>/dev/null +} + +#------------------------------------------------------------------------------ +# Function - psplash_message +# +# Shows the given message in the psplash screen. +# +# @param ${1} - Message to show. +#------------------------------------------------------------------------------ +psplash_message() { + echo "MSG ${1}" > /tmp/psplash_fifo + sleep 0.2 +} + +#------------------------------------------------------------------------------ +# Function - psplash_progress +# +# Sets the psplash progress bar percentage to the given one. +# +# @param ${1} - Progress percentage. +#------------------------------------------------------------------------------ +psplash_progress() { + echo "PROGRESS ${1}" > /tmp/psplash_fifo + sleep 0.2 +} + +#------------------------------------------------------------------------------ +# Function - reboot_system +# +# Reboots the system. +#------------------------------------------------------------------------------ +reboot_system() { + sync && reboot -f +} + +#------------------------------------------------------------------------------ +# Function - quit_with_error +# +# Ends the recovery process with the given error message. +# +# @param ${1} - Error message. +#------------------------------------------------------------------------------ +quit_with_error() { + clear_uboot_vars + log_error "${1}" + log "The system will now reboot in ${REBOOT_TIME} seconds" + sleep "${REBOOT_TIME}" + reboot_system +} + +#------------------------------------------------------------------------------ +# Function - is_nand +# +# Verifies if the system is running in a NAND flash. +# +# @return - "yes" if the system is running in NAND, "no" otherwise +#------------------------------------------------------------------------------ +is_nand() { + if [ -f /proc/mtd ] && grep -qs mtd /proc/mtd; then + echo "yes" + else + echo "no" + fi +} + +#------------------------------------------------------------------------------ +# Function - format_partition +# +# Formats the given partition. +# +# @param ${1} - Partition name to format. +#------------------------------------------------------------------------------ +format_partition() { + if [ "$(is_nand)" = "yes" ]; then + format_ubi_volume "${1}" + else + format_emmc_block "${1}" + fi +} + +#------------------------------------------------------------------------------ +# Function - format_ubi_volume +# +# Formats and re-creates the given UBI volume. +# +# @param ${1} - UBI Volume name to format. +#------------------------------------------------------------------------------ +format_ubi_volume() { + # Find the MTD partition. + local mtd_num="$(sed -ne "s/mtd\([0-9]\+\):.*\<${1}\>.*/\1/g;T;p" /proc/mtd 2>/dev/null)" + if [ -z "${mtd_num}" ]; then + quit_with_error "Could not find MTD partition for volume '${1}'" + else + # Umount in case partition is mounted, ignore errors. + if grep -qs "${1}" /proc/mounts; then + local path="$(sed -ne "s/.*:${1} \(.*\) ubifs.*/\1/g;T;p" /proc/mounts 2>/dev/null)" + umount "${path}" >/dev/null 2>&1 + fi + ubidetach -p "/dev/mtd${mtd_num}" >/dev/null 2>&1 + # Format MTD partition. + if ! ubiformat "/dev/mtd${mtd_num}" -q -y; then + quit_with_error "Error erasing '/dev/mtd${mtd_num}' block" + fi + psplash_progress "50" + # Attach and get UBI device number + local dev_number="$(ubiattach -p /dev/mtd${mtd_num} 2>/dev/null | sed -ne 's,.*device number \([0-9]\).*,\1,g;T;p' 2>/dev/null)" + # Create UBI Vol. + ubimkvol "/dev/ubi${dev_number}" -m -N "${1}" >/dev/null 2>&1 + if [ "$?" = "0" ]; then + # Configure the empty UBIFS partition to use ZLIB + [ "${1}" = "update" ] && UBIFS_COMPRESSION="-x zlib" + + volid="$(ubinfo "/dev/ubi${dev_number}" -N "${1}" | sed -ne 's,Volume ID:[[:blank:]]\+\([0-9]\+\)[[:blank:]]\+.*,\1,g;T;p')" + mkfs.ubifs ${UBIFS_COMPRESSION} -F /dev/ubi${dev_number}_${volid} + psplash_progress "100" + log "Partition '${1}' successfully erased!" + # Detach MTD partition. + ubidetach -p "/dev/mtd${mtd_num}" >/dev/null 2>&1 + else + quit_with_error "Error creating '${1}' UBI volume" + fi + fi +} + +#------------------------------------------------------------------------------ +# Function - format_emmc_block +# +# Formats the given emmc partition block name. +# +# @param ${1} - Partition name to format. +#------------------------------------------------------------------------------ +format_emmc_block() { + # Find partition block number. + local partition_block="/dev/mmcblk0p$(parted -s /dev/mmcblk0 print | sed -ne "s,^[^0-9]*\([0-9]\+\).*\<${1}\>.*,\1,g;T;p")" + if [ -b "${partition_block}" ]; then + # Umount in case partition is mounted, ignore errors. + if grep -qs "${partition_block}" /proc/mounts; then + umount "${partition_block}" >/dev/null 2>&1 + fi + # Format emmc block. + mkfs.ext4 "${partition_block}" >/dev/null 2>&1 + if [ "$?" = "0" ]; then + psplash_progress "100" + log "Partition '${1}' successfully erased!" + else + quit_with_error "Error erasing '${1}' partition" + fi + else + quit_with_error "Could not find partition block for '${1}'" + fi +} + +#------------------------------------------------------------------------------ +# Function - swu_package_path +# +# Get absolute path of update package searching in local media +# +# @param ${1} - SWU package +#------------------------------------------------------------------------------ +swu_package_path() { + # Check whether the package is local and get the absolute path. + if echo "${1}" | grep -qs '^file://'; then + local pkg_name="$(basename ${1})" + + for i in ${UPDATE_MOUNT_DIR} $(echo ${USB_MOUNT_DIR}/*); do + echo $i | grep -qs "${USB_MOUNT_DIR}/\*" && continue + if [ -f "${i}/${pkg_name}" ]; then + swu_abspath="${i}/${pkg_name}" + break + fi + done + + if [ -n "${swu_abspath}" ]; then + echo "${swu_abspath}" + else + quit_with_error "Unable to find update package '${pkg_name}'" + fi + else + echo "${1}" + fi +} + +#------------------------------------------------------------------------------ +# Function - check_swu_package +# +# Check if the update package is a valid one and get its absolute path +# +# @param ${1} - SWU package +#------------------------------------------------------------------------------ +check_swu_package() { + log "Checking update package '$(basename ${1})'" + + if [ -z "${1}" ]; then + quit_with_error "Firmware update package not specified" + fi + + update_package="$(swu_package_path ${1})" + + # Check software update package. + if [ -f "${PUBLIC_KEY}" ]; then + swupdate -c -i "${update_package}" -k "${PUBLIC_KEY}" + else + swupdate -c -i "${update_package}" + fi + + if [ "$?" != "0" ]; then + quit_with_error "Invalid update package '$(basename ${1})'" + fi +} + +# Main +#------------------------------------------------------------------------------ +# Setup the environment. +export PATH=/bin:/sbin:/usr/bin:/usr/sbin + +# Mount virtual file system. +mkdir -p /proc /sys /dev /tmp +mount -t proc proc /proc +mount -t sysfs sysfs /sys +mount -t devtmpfs devtmpfs /dev +mount -t tmpfs tmpfs /tmp +mount -t debugfs debugfs /sys/kernel/debug + +# Register mdev as device manager +if [ -f /proc/sys/kernel/hotplug ]; then + echo > /dev/mdev.seq + echo > /dev/mdev.log + echo "/sbin/mdev" > /proc/sys/kernel/hotplug + mdev -s +fi + +# Give some time for the devices to settle down +sleep 2 + +# Run all shell scripts in postinstall folder +run-parts /etc/*-postinsts + +# Setup fw_printenv. +rm -f /var/lock +mkdir -p /var/lock + +# Set kernel console loglevel. +sysctl -q -w kernel.printk=4 + +if [ "$(is_nand)" = "no" ]; then + # Launch 'rngd' to feed random data to kernel entropy pool + mkdir -p /var/run && rngd +fi + +# Parse the kernel command line. +for arg in $(cat /proc/cmdline); do + case "${arg}" in + rescue=1) eval "${arg}";; + esac +done + +# Jump to a rescue shell if requested. +if [ -n "${rescue}" ]; then + # Expand console and respawn if exited + while true; do + setsid cttyhack sh -l + export PATH=/bin:/sbin:/usr/bin:/usr/sbin + sleep 1 + done +fi + +log "Starting recovery..." + +if [ -b /dev/mmcblk0p1 ]; then + log "sdcard is exist" +else + quit_with_error "sdcard is exist" +fi + + +update_package=`find /run/media/ -name "*.swu"` +if [ "x${update_package}" == "x" ]; then + quit_with_error "Can not found the update package" +else + log "The update file is ${update_package}" +fi + +swupdate -i ${update_package} +if [ "$?" = "0" ]; then + log "Firmware update process succeed!" +else + quit_with_error "Error executing the firmware update" +fi + +#clear_uboot_vars +reboot_system diff --git a/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/swupdate.cfg b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/swupdate.cfg new file mode 100644 index 0000000..2a63bee --- /dev/null +++ b/meta-i2som-yocto/recipes-core/recovery/recovery-initramfs/swupdate.cfg @@ -0,0 +1,7 @@ +globals : +{ + verbose = true; + loglevel = 5; + syslog = true; + mtd-blacklist = "0 1 2"; +};