| #!/bin/sh |
| |
| # Get the root mtd device number (mtdX) from "/dev/ubiblockX_Y on /" |
| findrootmtd() { |
| rootmatch=" on / " |
| m="$(mount | grep "${rootmatch}" | grep "ubiblock")" |
| m="${m##*ubiblock}" |
| m="${m%_*}" |
| if [ -z "${m}" ]; then |
| # default to bmc mtd (0) |
| m=0 |
| fi |
| echo "mtd${m}" |
| } |
| |
| findrootubi() { |
| rootmatch=" on / " |
| m="$(mount | grep "${rootmatch}")" |
| m="${m##*ubiblock}" |
| m="${m% on*}" |
| echo "ubi${m}" |
| } |
| |
| # Get the mtd device number (mtdX) |
| findmtd() { |
| m="$(grep -xl "$1" /sys/class/mtd/*/name)" |
| m="${m%/name}" |
| m="${m##*/}" |
| echo "${m}" |
| } |
| |
| # Get the ubi device number (ubiX_Y) |
| findubi() { |
| u="$(grep -xl "$1" /sys/class/ubi/ubi?/subsystem/ubi*/name)" |
| u="${u%/name}" |
| u="${u##*/}" |
| echo "${u}" |
| } |
| |
| # Get the ubi device number (ubiX_Y) on a specific mtd |
| findubi_onmtd() { |
| u="$(grep -xl "$1" /sys/class/ubi/ubi"$2"/subsystem/ubi"$2"*/name)" |
| u="${u%/name}" |
| u="${u##*/}" |
| echo "${u}" |
| } |
| |
| # Get all ubi device names on a specific mtd that match requested string |
| findubiname_onmtd() { |
| u="$(grep -h "$1" /sys/class/ubi/ubi"$2"/subsystem/ubi"$2"*/name)" |
| u="${u%/name}" |
| u="${u##*/}" |
| echo "${u}" |
| } |
| |
| # Get the name from the requested ubiX_Y volume |
| findname() { |
| n="$(cat /sys/class/ubi/$1/name)" |
| echo "${n}" |
| } |
| |
| # Make space on flash before creating new volumes. This can be enhanced |
| # determine current flash usage. For now only keep a "keepmax" number of them |
| ubi_remove_volumes() |
| { |
| rootubi="$(findrootubi)" |
| rootname="$(findname "${rootubi}")" |
| rootversion="${rootname##*-}" |
| rootkernel="kernel-${rootversion}" |
| |
| # Just keep max number of volumes before updating, don't delete the version |
| # the BMC is booted from, and when a version is identified to be deleted, |
| # delete both the rofs and kernel volumes for that version. |
| rmnames="$(findubiname_onmtd "${name%-*}-" "${ro}")" |
| rmnames=(${rmnames}) |
| ubicount="${#rmnames[@]}" |
| while [ ${ubicount} -ge ${keepmax} ]; do |
| # Loop through existing volumes and skip currently active ones |
| for (( index=0; index<${#rmnames[@]}; index++ )); do |
| rmname="${rmnames[${index}]}" |
| rmversion="${rmname##*-}" |
| [ "${rmversion}" == "${version}" ] && continue |
| rmubi="$(findubi_onmtd "rofs-${rmversion}" "${ro}")" |
| if [[ ( "${rmubi}" != "${rootubi}" ) && |
| ( "${rmname}" != "${rootkernel}" ) ]]; then |
| ubi_remove "rofs-${rmversion}" "${ro}" |
| ubi_remove "kernel-${rmversion}" "${ro}" |
| # Remove priority value |
| fw_setenv "${rmversion}" |
| break |
| fi |
| done |
| # Decrease count regardless to avoid an infinite loop |
| (( ubicount-- )) |
| done |
| } |
| |
| ubi_rw() { |
| rwmtd="$(findmtd "${reqmtd}")" |
| rw="${rwmtd#mtd}" |
| ubidev="/dev/ubi${rw}" |
| |
| # Create a ubi volume of size 4MB, that is the current size of the rwfs image |
| vol="$(findubi "${name}")" |
| if [ -z "${vol}" ]; then |
| ubimkvol "${ubidev}" -N "${name}" -s 4MiB |
| fi |
| } |
| |
| ubi_ro() { |
| keepmax=2 # Default 2 volumes per mtd |
| romtd="$(findmtd "${reqmtd}")" |
| romtd2="$(findmtd "${reqmtd2}")" |
| |
| if [ ! "${romtd}" == "${romtd2}" ]; then |
| # Request to use alternate mtd device, choose the non-root one |
| keepmax=1 # 1 volume on each of the requested mtds |
| rootmtd="$(findrootmtd)" |
| if [ "${rootmtd}" == "${romtd}" ]; then |
| romtd="${romtd2}" |
| fi |
| fi |
| ro="${romtd#mtd}" |
| ubidev="/dev/ubi${ro}" |
| |
| ubi_remove_volumes |
| |
| # Create a static ubi volume |
| # TODO Get the actual image size openbmc/openbmc#1840 |
| vol="$(findubi "${name}")" |
| if [ ! -z "${vol}" ]; then |
| # Allow a duplicate kernel volume on the alt mtd |
| if [[ "${name}" =~ "kernel" ]]; then |
| vol="$(findubi_onmtd "${name}" "${ro}")" |
| fi |
| fi |
| if [ -z "${vol}" ]; then |
| ubimkvol "${ubidev}" -N "${name}" -s "${imgsize}" --type=static |
| vol="$(findubi "${name}")" |
| fi |
| } |
| |
| # Squashfs images need a ubi block |
| ubi_block() { |
| vol="$(findubi "${name}")" |
| ubidevid="${vol#ubi}" |
| block="/dev/ubiblock${ubidevid}" |
| if [ ! -e "$block" ]; then |
| ubiblock --create "/dev/ubi${ubidevid}" |
| if [ $? != 0 ]; then |
| echo "Unable to create ubiblock ${name}:${ubidevid}" |
| return 1 |
| fi |
| fi |
| } |
| |
| ubi_updatevol() { |
| vol="$(findubi "${name}")" |
| ubidevid="${vol#ubi}" |
| img="/tmp/images/${version}/${imgfile}" |
| ubiupdatevol "/dev/ubi${ubidevid}" "${img}" |
| if [ $? != 0 ]; then |
| echo "Unable to update volume ${name}!" |
| return 1 |
| fi |
| } |
| |
| ubi_remove() { |
| rmname="$1" |
| rmmtd="$2" |
| if [ ! -z "${rmmtd}" ]; then |
| vol="$(findubi_onmtd "${rmname}" "${rmmtd}")" |
| else |
| vol="$(findubi "${rmname}")" |
| fi |
| |
| if [ ! -z "$vol" ]; then |
| vol="${vol%_*}" |
| |
| if grep -q "$rmname" /proc/mounts; then |
| mountdir=$(grep "$rmname" /proc/mounts | cut -d " " -f 2) |
| umount "$mountdir" |
| rm -r "$mountdir" |
| fi |
| |
| ubirmvol "/dev/${vol}" -N "$rmname" |
| fi |
| } |
| |
| ubi_cleanup() { |
| # When ubi_cleanup is run, it expects one or no active version. |
| activeVersion=$(busctl --list --no-pager tree \ |
| xyz.openbmc_project.Software.BMC.Updater | \ |
| grep /xyz/openbmc_project/software/ | tail -c 9) |
| |
| if [[ -z "$activeVersion" ]]; then |
| vols=$(ubinfo -a | grep -e "kernel-" -e "rofs-" | cut -c 14-) |
| vols=(${vols}) |
| else |
| vols=$(ubinfo -a | grep -e "kernel-" -e "rofs-" | \ |
| grep -v "$activeVersion" | cut -c 14-) |
| vols=(${vols}) |
| fi |
| |
| for (( index=0; index<${#vols[@]}; index++ )); do |
| ubi_remove ${vols[index]} |
| done |
| } |
| |
| remount_ubi() { |
| bmcmtd="$(findmtd "bmc")" |
| altbmcmtd="$(findmtd "alt-bmc")" |
| mtds="${bmcmtd: -1}","${altbmcmtd: -1}" |
| |
| IFS=',' read -r -a mtds <<< "$mtds" |
| mtds=($(echo "${mtds[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) |
| for mtd in ${mtds[@]}; do |
| # Re-attach mtd device to ubi if not already done |
| ubiattach /dev/ubi_ctrl -m "${mtd}" -d "${mtd}" &> /dev/null |
| # Get information on all ubi volumes |
| ubinfo=$(ubinfo -d ${mtd}) |
| presentVolumes=${ubinfo##*:} |
| IFS=', ' read -r -a array <<< "$presentVolumes" |
| for element in ${array[@]}; do |
| elementProperties=$(ubinfo -d $mtd -n $element) |
| # Get ubi volume name by getting rid of additional properties |
| name=${elementProperties#*Name:} |
| name="${name%Character*}" |
| name="$(echo -e "${name}" | tr -d '[:space:]')" |
| |
| if [[ ${name} == rofs-* ]]; then |
| mountdir="/media/${name}" |
| |
| if [ ! -d ${mountdir} ]; then |
| mkdir -p "${mountdir}" |
| ubiblock --create /dev/ubi${mtd}_${element} &> /dev/null |
| mount -t squashfs -o ro "/dev/ubiblock${mtd}_${element}" "${mountdir}" |
| fi |
| fi |
| done |
| done |
| } |
| |
| # Read the current env variable and set it on the alternate boot env |
| copy_env_var_to_alt() { |
| varName=$1 |
| value="$(fw_printenv -n "${varName}")" |
| fw_setenv -c /etc/alt_fw_env.config "${varName}" "${value}" |
| } |
| |
| ubi_setenv() { |
| variable=$1 |
| if [[ "$variable" == *"="* ]]; then |
| varName="${variable%=*}" |
| value="${variable##*=}" |
| fw_setenv "$varName" "$value" |
| else |
| fw_setenv "$variable" |
| fi |
| } |
| |
| mtd_write() { |
| flashmtd="$(findmtd "${reqmtd}")" |
| img="/tmp/images/${version}/${imgfile}" |
| flashcp -v ${img} /dev/${flashmtd} |
| } |
| |
| backup_env_vars() { |
| copy_env_var_to_alt kernelname |
| copy_env_var_to_alt ubiblock |
| copy_env_var_to_alt root |
| } |
| |
| update_env_vars() { |
| vol="$(findubi rofs-"${version}")" |
| if [ -z "${vol}" ]; then |
| return 1 |
| fi |
| ubidevid="${vol#ubi}" |
| block="/dev/ubiblock${ubidevid}" |
| if [ ! -e "${block}" ]; then |
| return 1 |
| fi |
| ubi_setenv "kernelname=kernel-${version}" |
| ubi_setenv "ubiblock=$(echo "${ubidevid}" | sed 's/_/,/')" |
| ubi_setenv "root=${block}" |
| } |
| |
| #TODO: Replace the implementation with systemd-inhibitors lock |
| # once systemd/systemd#949 is resolved |
| rebootguardenable() { |
| dir="/run/systemd/system/" |
| file="reboot-guard.conf" |
| units=("reboot" "poweroff" "halt") |
| |
| for unit in "${units[@]}"; do |
| mkdir -p ${dir}${unit}.target.d |
| echo -e "[Unit]\nRefuseManualStart=yes" >> ${dir}${unit}.target.d/${file} |
| done |
| } |
| |
| #TODO: Replace the implementation with systemd-inhibitors lock |
| # once systemd/systemd#949 is resolved |
| rebootguarddisable() { |
| dir="/run/systemd/system/" |
| file="reboot-guard.conf" |
| units=("reboot" "poweroff" "halt") |
| |
| for unit in "${units[@]}"; do |
| rm -rf ${dir}${unit}.target.d/${file} |
| done |
| } |
| |
| # Create a copy in the alt mtd |
| create_vol_in_alt() { |
| alt="alt-bmc" |
| altmtd="$(findmtd "${alt}")" |
| if [ ! -z "${altmtd}" ]; then |
| reqmtd="${alt}" |
| reqmtd2="${alt}" |
| ubi_ro |
| ubi_updatevol |
| fi |
| } |
| |
| factory_reset() { |
| # A lock file for printenv exists on /var, which isn't mounted when this |
| # function is called. We have to read the rwreset variable out of file. |
| ubootmtd="$(findmtd "u-boot-env")" |
| grep -q -x "rwreset=true" /dev/$ubootmtd |
| if [ "$?" = "0" ]; then |
| ubi_remove "rwfs" |
| reqmtd="bmc" |
| name="rwfs" |
| ubi_rw |
| fi |
| } |
| |
| case "$1" in |
| mtduboot) |
| reqmtd="$2" |
| version="$3" |
| imgfile="image-u-boot" |
| mtd_write |
| ;; |
| ubirw) |
| reqmtd="$2" |
| name="$3" |
| ubi_rw |
| ;; |
| ubiro) |
| reqmtd="$(echo "$2" | cut -d "+" -f 1)" |
| reqmtd2="$(echo "$2" | cut -d "+" -f 2)" |
| name="$3" |
| version="$4" |
| imgfile="image-rofs" |
| imgsize="16MiB" |
| ubi_ro |
| ubi_updatevol |
| ubi_block |
| ;; |
| ubikernel) |
| reqmtd="$(echo "$2" | cut -d "+" -f 1)" |
| reqmtd2="$(echo "$2" | cut -d "+" -f 2)" |
| name="$3" |
| version="$4" |
| imgfile="image-kernel" |
| imgsize="4MiB" |
| ubi_ro |
| ubi_updatevol |
| create_vol_in_alt |
| ;; |
| ubiremove) |
| name="$2" |
| ubi_remove "${name}" |
| ;; |
| ubicleanup) |
| ubi_cleanup |
| ;; |
| ubisetenv) |
| ubi_setenv "$2" |
| ;; |
| ubiremount) |
| remount_ubi |
| ;; |
| createenvbackup) |
| backup_env_vars |
| ;; |
| updateubootvars) |
| version="$2" |
| update_env_vars |
| ;; |
| rebootguardenable) |
| rebootguardenable |
| ;; |
| rebootguarddisable) |
| rebootguarddisable |
| ;; |
| reset) |
| factory_reset |
| ;; |
| *) |
| echo "Invalid argument" |
| exit 1 |
| ;; |
| esac |
| rc=$? |
| if [ ${rc} -ne 0 ]; then |
| echo "$0: error ${rc}" |
| exit ${rc} |
| fi |