From 878cae948d00cfc45e819bb4d5c135727dcaa366 Mon Sep 17 00:00:00 2001 From: TheKit Date: Wed, 23 Sep 2020 22:40:44 +0300 Subject: [PATCH] ramdisk-overlay: fix locating systempart on A/B devices --- ramdisk-overlay/scripts/halium | 660 +++++++++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100755 ramdisk-overlay/scripts/halium diff --git a/ramdisk-overlay/scripts/halium b/ramdisk-overlay/scripts/halium new file mode 100755 index 0000000..fadbd57 --- /dev/null +++ b/ramdisk-overlay/scripts/halium @@ -0,0 +1,660 @@ +# Local filesystem mounting -*- shell-script -*- + +_log_msg() { + if [ "$quiet" = "y" ]; then return; fi + printf "$@" > /dev/kmsg || true +} + +pre_mountroot() { + [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top" + run_scripts /scripts/local-top + [ "$quiet" != "y" ] && log_end_msg +} + +tell_kmsg() { + # Echos a string into /dev/kmsg, ignoring errors. + echo "initrd: $1" >/dev/kmsg || true +} + +halium_panic() { + # Puts panic reason into kmsg and then starts the panic handlers + REASON="$1" + tell_kmsg "PANIC for reason: $REASON" + panic $REASON +} + +identify_boot_mode() { + # Our current list of supported boot modes: + ## BOOT_MODE = halium and android + BOOT_MODE='halium' + + # The boot reason is exported via /proc/cmdline + # The standard method is using androidboot.mode parameter. + + for x in $(cat /proc/cmdline); do + case ${x} in + androidboot.mode=*) + android_bootmode=${x#*=} + ;; + esac + done + + if echo "$android_bootmode" | grep charger; then + BOOT_MODE="android" + fi + + ## Some devices may be using 'bootreason', others 'boot_reason' + ## XXX: Find a better way to handle device specifics here + + # Krillin + if [ -f /sys/class/BOOT/BOOT/boot/boot_mode ]; then + boot_reason=$(cat /sys/class/BOOT/BOOT/boot/boot_mode) + case "${boot_reason}" in + 1) BOOT_MODE="android" ;; # Meta + 4) BOOT_MODE="android" ;; # Factory + 8) BOOT_MODE="android" ;; # Power off charging + 9) BOOT_MODE="android" ;; # Low power charging + esac + fi + + tell_kmsg "boot mode: $BOOT_MODE" +} + +identify_android_image() { + # Checks for the provided Android image. If it's called system.img, it + # should be mounted at Android's /system. If it's called android-rootfs.img, + # it should be mounted at Android's /. + # Sets $ANDROID_IMAGE_MODE to: + # * "rootfs" if the image should be mounted at '/android/' + # * "system" if the image should be mounted at '/android/system/' + # * "unknown" if neither is found + + [ -f /tmpmnt/system.img ] && ANDROID_IMAGE_MODE="system" + [ -f /tmpmnt/android-rootfs.img ] && ANDROID_IMAGE_MODE="rootfs" + [ -f /halium-system/var/lib/lxc/android/system.img ] && ANDROID_IMAGE_MODE="system" + [ -f /halium-system/var/lib/lxc/android/android-rootfs.img ] && ANDROID_IMAGE_MODE="rootfs" + [ -z $ANDROID_IMAGE_MODE ] && ANDROID_IMAGE_MODE="unknown" +} + +set_halium_version_properties() { + halium_system=$1 + android_data=$2 + + channel_ini=$1/etc/system-image/channel.ini + def_language=$1/custom/default_language + + halium="unknown" + device="unknown" + custom="unknown" + version="unknown" + channel="unknown" + def_lang="unknown" + + if [ -f "$channel_ini" ]; then + IFS=',' + for i in $(grep version_detail $channel_ini | awk -F ' ' '{print $2}'); do + id=${i%=*} + case $id in + halium) halium=${i#halium=} ;; + device) device=${i#device=} ;; + custom) custom=${i#custom=} ;; + version) version=${i#version=} ;; + esac + done + unset IFS + channel=$(grep channel $channel_ini | awk -F ' ' '{print $2}') + fi + + if [ -f "$def_language" ]; then + lang=$(cat $def_language) + if [ -n "$lang" ]; then + def_lang=$lang + fi + fi + + # Write down so the android property system can load them automatically + mkdir -p $android_data/property + chmod 700 $android_data/property + echo -n "$halium" >$android_data/property/persist.halium.version.rootfs + echo -n "$device" >$android_data/property/persist.halium.version.device + echo -n "$custom" >$android_data/property/persist.halium.version.custom + echo -n "$channel" >$android_data/property/persist.halium.version.channel + echo -n "$version" >$android_data/property/persist.halium.version + echo -n "$def_lang" >$android_data/property/persist.halium.default_language + chmod 600 $android_data/property/persist.halium* +} + +mount_android_partitions() { + fstab=$1 + mount_root=$2 + real_userdata=$3 + + tell_kmsg "checking fstab $fstab for additional mount points" + + # On systems with A/B partition layout, current slot is provided via cmdline parameter. + ab_slot_suffix=$(grep -o 'androidboot\.slot_suffix=..' /proc/cmdline | cut -d "=" -f2) + [ ! -z "$ab_slot_suffix" ] && tell_kmsg "A/B slot system detected! Slot suffix is $ab_slot_suffix" + + cat ${fstab} | while read line; do + set -- $line + + # stop processing if we hit the "#endhalium" comment in the file + echo $1 | egrep -q "^#endhalium" && break + + # Skip any unwanted entry + echo $1 | egrep -q "^#" && continue + ([ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]) && continue + ([ "$2" = "/system" ] || [ "$2" = "/data" ] || [ "$2" = "/" ]) && continue + + label=$(echo $1 | awk -F/ '{print $NF}') + [ -z "$label" ] && continue + + tell_kmsg "checking mount label $label" + + # In case fstab provides /dev/mmcblk0p* lines + path="/dev/$label" + for dir in by-partlabel by-name by-label by-path by-uuid by-partuuid by-id; do + # On A/B systems not all of the partitions are duplicated, so we have to check with and without suffix + if [ -e "/dev/disk/$dir/$label$ab_slot_suffix" ]; then + path="/dev/disk/$dir/$label$ab_slot_suffix" + break + elif [ -e "/dev/disk/$dir/$label" ]; then + path="/dev/disk/$dir/$label" + break + fi + done + + [ ! -e "$path" ] && continue + + mkdir -p ${mount_root}/$2 + tell_kmsg "mounting $path as ${mount_root}/$2" + mount $path ${mount_root}/$2 -t $3 -o $4 + done + + # Provide a bind mount from /cache to /userdata/cache on systems without a dedicated cache partition + if [ ! -e ${mount_root}/cache ]; then + if [ ! -d ${real_userdata}/cache ]; then + mkdir ${real_userdata}/cache + fi + mkdir ${mount_root}/cache + mount -o bind ${real_userdata}/cache ${mount_root}/cache + fi + + # Create an appropriate symlink for vendor files + if [ ! -e ${mount_root}/vendor ]; then + ln -sf system/vendor ${mount_root}/vendor + fi +} + +mount_halium_overlay() { + source=$1 + target=$2 + + if [ -d ${source} ]; then + OLD_PWD=$PWD + cd ${source} + + for overlay in $(find . -type f); do + [ -f ${target}/${overlay} ] && mount --bind ${source}/${overlay} ${target}/${overlay} + done + + cd $OLD_PWD + fi +} + +sync_dirs() { + base=$1 + source=$2 + target=$3 + + OLD_PWD=$PWD + cd $base + + for file in $source/*; do + # Skip empty directories + [ ! -e "$base/$file" ] && continue + + # If the target already exists as a file or link, there's nothing we can do + [ -e "$target/$file" -o -L "$target/$file" ] && [ ! -d "$target/$file" ] && continue + + # If the target doesn't exist, just copy it over + if [ ! -e "$target/$file" -a ! -L "$target/$file" ]; then + cp -Ra "$base/$file" "$target/$file" + continue + fi + + # That leaves us with directories and a recursive call + [ -d $file ] && sync_dirs $base $file $target + done + + cd $OLD_PWD +} + +resize_userdata_if_needed() { + + # See if the filesystem on the userdata partition needs resizing (usually on first boot). + # If the difference between the partition size and the filesystem size is above a small + # threshold, assume it needs resizing to fill the partition. + + path=$1 + + # Partition size in 1k blocks + case $path in + /dev/mmcblk*) + pblocks=$(grep ${path#/dev/*} /proc/partitions | awk {'print $3'}) + ;; + /dev/disk*) + pblocks=$(grep $(basename $(readlink $path)) /proc/partitions | awk {'print $3'}) + ;; + esac + # Filesystem size in 4k blocks + fsblocks=$(dumpe2fs -h $path | grep "Block count" | awk {'print $3'}) + # Difference between the reported sizes in 1k blocks + dblocks=$((pblocks - 4 * fsblocks)) + if [ $dblocks -gt 10000 ]; then + resize2fs -f $path + tell_kmsg "resized userdata filesystem to fill $path" + fi +} + +identify_file_layout() { + # Determine if we have a Halium rootfs.img & system.img + + # $file_layout = "halium" means there is a separate rootfs.img and system.img on userdata + # + # = "partition" means the rootfs is located on the device's system partition + # and will contain /var/lib/lxc/android/system.img + # + # = "subdir" means the rootfs is located in a folder on the device's userdata partition + # and will contain /var/lib/lxc/android/system.img + + if [ -e /tmpmnt/rootfs.img ]; then + imagefile=/tmpmnt/rootfs.img + file_layout="halium" + elif [ -d /tmpmnt/halium-rootfs ]; then + imagefile=/tmpmnt/halium-rootfs + file_layout="subdir" + else + file_layout="partition" + fi + +} + +process_bind_mounts() { + # Goes over /etc/system-image/writable-paths to create the correct fstab for + # the bind-mounts. Writes them into ${rootmnt}/run/image.fstab which is + # bind-mounted to /etc/fstab + + if [ ! -e ${rootmnt}/etc/system-image/writable-paths ]; then + tell_kmsg "This rootfs does not have any writable-paths defined" + return 0 + fi + + # Mount a tmpfs in /run of rootfs to put the future image.fstab + mount -o rw,nosuid,noexec,relatime,mode=755 -t tmpfs tmpfs ${rootmnt}/run + # Prepare the fstab + FSTAB=${rootmnt}/etc/fstab + touch ${rootmnt}/run/image.fstab + mount -o bind ${rootmnt}/run/image.fstab $FSTAB ||halium_panic "Could not bind-mount fstab" + echo "/dev/root / rootfs defaults,ro 0 0" >>$FSTAB + + tell_kmsg "Adding bind-mounts to $FSTAB" + # Process the list of bind-mounts + # (but don't mount them, mountall will do it) + cat ${rootmnt}/etc/system-image/writable-paths | while read line; do + set -- $line + # Skip invalid/commented entries + ([ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ] || [ -z "$5" ]) && continue + [ "$1" = "#" ] && continue + + # Skip invalid mount points + dstpath="${rootmnt}/$1" + [ ! -e "$dstpath" ] && continue + + if [ "$3" = "temporary" ]; then + # Temporary entries are simple, just mount a tmpfs + echo "tmpfs $1 tmpfs $5 0 0" >>$FSTAB + elif [ "$3" = "persistent" ] || [ "$3" = "synced" ]; then + # Figure out the source path + if [ "$2" = "auto" ]; then + srcpath="${rootmnt}/userdata/system-data/$1" + path="/userdata/system-data/$1" + else + srcpath="${rootmnt}/userdata/$2" + path="/userdata/$2" + fi + + if [ ! -e "$srcpath" ]; then + # Process new persistent or synced paths + dstown=$(stat -c "%u:%g" $dstpath) + dstmode=$(stat -c "%a" $dstpath) + mkdir -p ${srcpath%/*} + if [ ! -d "$dstpath" ]; then + # Deal with redirected files + if [ "$4" = "transition" ]; then + cp -a $dstpath $srcpath + else + touch $srcpath + chown $dstown $srcpath + chmod $dstmode $srcpath + fi + else + # Deal with redirected directories + if [ "$4" = "transition" ] || [ "$3" = "synced" ]; then + cp -aR $dstpath $srcpath + else + mkdir $srcpath + chown $dstown $srcpath + chmod $dstmode $srcpath + fi + fi + elif [ "$3" = "synced" ]; then + # Process existing synced paths + sync_dirs $dstpath . $srcpath + fi + + # Write the fstab entry + if [ "$5" = "none" ]; then + echo "$path $1 none bind 0 0" >>$FSTAB + else + echo "$path $1 none bind,$5 0 0" >>$FSTAB + fi + else + continue + fi + done +} + +extract_android_ramdisk() { + # Extracts the ramdisk from /android-system/boot/android-ramdisk.img to + # /android-rootfs + + # NOTE: we should find a faster way of doing that or cache it + tell_kmsg "extracting android ramdisk" + OLD_CWD=$(pwd) + mount -n -t tmpfs tmpfs /android-rootfs + cd /android-rootfs + cat /android-system/boot/android-ramdisk.img | gzip -d | cpio -i + cd $OLD_CWD +} + +mount_kernel_modules() { + # Bind-mount /lib/modules from Android + [ -e ${rootmnt}/android/system/lib/modules ] && mount --bind ${rootmnt}/android/system/lib/modules ${rootmnt}/lib/modules +} + +mountroot() { + # list of possible userdata partition names + partlist="userdata UDA DATAFS USERDATA" + + pre_mountroot + + [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount" + run_scripts /scripts/local-premount + [ "$quiet" != "y" ] && log_end_msg + + # Put all of this script's output into /dev/kmsg + exec &>/dev/kmsg + + # Mount root + # + # Create a temporary mountpoint for the bindmount + mkdir -p /tmpmnt + + # Make sure the device has been created by udev before we try to mount + udevadm settle + + # find the right partition + for partname in $partlist; do + part=$(find /dev -name $partname | tail -1) + [ -z "$part" ] && continue + path=$(readlink -f $part) + [ -n "$path" ] && break + done + + # On systems with A/B partition layout, current slot is provided via cmdline parameter. + ab_slot_suffix=$(grep -o 'androidboot\.slot_suffix=..' /proc/cmdline | cut -d "=" -f2) + if [ -z "$path" ] && [ ! -z "$ab_slot_suffix" ] ; then + tell_kmsg "Searching for A/B data partition on slot $ab_slot_suffix." + + for partname in $partlist; do + part=$(find /dev -name "$partname$ab_slot_suffix" | tail -1) + [ -z "$part" ] && continue + path=$(readlink -f $part) + [ -n "$path" ] && break + done + fi + + # override with a possible cmdline parameter + if grep -q datapart= /proc/cmdline; then + for x in $(cat /proc/cmdline); do + case ${x} in + datapart=*) + path=${x#*=} + ;; + esac + done + fi + + if [ -z "$path" ]; then + halium_panic "Couldn't find data partition." + fi + + tell_kmsg "checking filesystem integrity for the userdata partition" + # Mounting and umounting first, let the kernel handle the journal and + # orphaned inodes (faster than e2fsck). Then, just run e2fsck forcing -y. + # Also check the amount of time used by to check the filesystem. + fsck_start=$(date +%s) + mount -o errors=remount-ro $path /tmpmnt + umount /tmpmnt + e2fsck -y $path >/run/e2fsck.out 2>&1 + fsck_end=$(date +%s) + tell_kmsg "checking filesystem for userdata took (including e2fsck) $((fsck_end - fsck_start)) seconds" + + resize_userdata_if_needed ${path} + + tell_kmsg "mounting $path" + + # Mount the data partition to a temporary mount point + # FIXME: data=journal used on ext4 as a workaround for bug 1387214 + [ `blkid $path -o value -s TYPE` = "ext4" ] && OPTIONS="data=journal," + mount -o discard,$OPTIONS $path /tmpmnt + + # Set $_syspart if it is specified as systempart= on the command line + if grep -q systempart= /proc/cmdline; then + for x in $(cat /proc/cmdline); do + case ${x} in + systempart=*) + _syspart=${x#*=} + ;; + esac + done + fi + + if [ -n "$_syspart" ] && [ ! -e "$_syspart" ]; then + # On systems with A/B partition layout, current slot is provided via cmdline parameter. + ab_slot_suffix=$(grep -o 'androidboot\.slot_suffix=..' /proc/cmdline | cut -d "=" -f2) + if [ ! -z "$ab_slot_suffix" ]; then + tell_kmsg "A/B slot system detected! Slot suffix is $ab_slot_suffix" + _syspart="${_syspart}${ab_slot_suffix}" + tell_kmsg "system partition is at $_syspart" + fi + fi + + identify_boot_mode + identify_file_layout + + # If both $imagefile and $_syspart are set, something is wrong. The strange + # output from this could be a clue in that situation. + tell_kmsg "Halium rootfs is $imagefile $_syspart" + + # Prepare the root filesystem + # NOTE: We mount it read-write in all cases, then remount read-only. + # This is to workaround a behaviour change in busybox which now + # uses read-only loops if the fs is initially mounted read-only. + # An alternative implementation would be to add losetup support + # to busybox and do the mount in two steps (rw loop, ro fs). + + mkdir -p /halium-system + + tell_kmsg "mounting system rootfs at /halium-system" + if [ -n "$_syspart" ]; then + mount -o rw $_syspart /halium-system + elif [ -f "$imagefile" ]; then + # Rootfs is an image file + mount -o loop,rw $imagefile /halium-system + elif [ -d "$imagefile" ]; then + # Rootfs is a directory + mount -o bind /tmpmnt/halium-rootfs /halium-system + fi + + # Identify image mode: either "rootfs" or "system" + mkdir -p /android-rootfs + mkdir -p /android-system + + identify_android_image + [ $ANDROID_IMAGE_MODE = "unknown" ] && tell_kmsg "WARNING: Android system image not found." + + # If either (android) /data/.writable_image or (on rootfs) + # /.writable_image exist, mount the rootfs as rw + if [ -e /tmpmnt/.writable_image ] || [ -e /halium-system/.writable_image ]; then + tell_kmsg "mounting $_syspart $imagefile (image developer mode)" + mountroot_status="$?" + else + # Neither of those exist, remount read-only + tell_kmsg "mounting $_syspart $imagefile (user mode)" + mount -o remount,ro /halium-system + mountroot_status="$?" + fi + + # Mount the android system partition to a temporary location + MOUNT="ro" + MOUNT_LOCATION="/android-$ANDROID_IMAGE_MODE" + [ $ANDROID_IMAGE_MODE = "system" ] && ANDROID_IMAGE="system.img" || ANDROID_IMAGE="android-rootfs.img" + [ -e /tmpmnt/.writable_device_image -o -e /halium-system/.writable_device_image ] && MOUNT="rw" + tell_kmsg "mounting android system image (/tmpmnt/$ANDROID_IMAGE) $MOUNT, in $MOUNT_LOCATION ($ANDROID_IMAGE_MODE mode)" + if [ $file_layout = "halium" ]; then + # rootfs.img and Android system.img are separate + tell_kmsg "mounting android system image from userdata partition" + mount -o loop,$MOUNT "/tmpmnt/$ANDROID_IMAGE" $MOUNT_LOCATION + else + # Android system.img is inside rootfs + tell_kmsg "mounting android system image from system rootfs" + mount -o loop,$MOUNT "/halium-system/var/lib/lxc/android/$ANDROID_IMAGE" $MOUNT_LOCATION + fi + + [ $? -eq 0 ] || tell_kmsg "WARNING: Failed to mount Android system.img." + + [ $ANDROID_IMAGE_MODE = "rootfs" ] && mount -o bind $MOUNT_LOCATION/system /android-system + [ $ANDROID_IMAGE_MODE = "system" ] && extract_android_ramdisk + + # Determine whether we should boot to rootfs or Android + if ([ -e $imagefile ] || [ -n "$_syspart" ]) && [ "$BOOT_MODE" = "android" ]; then + # Bootloader says this is factory or charger mode, boot into Android. + tell_kmsg "Android boot mode for factory or charger mode" + + mount --move /android-rootfs ${rootmnt} + [ $ANDROID_IMAGE_MODE = "system" ] && mount --move /android-system ${rootmnt}/system + + # Mount all the Android partitions + mount_android_partitions "${rootmnt}/fstab*" ${rootmnt} /tmpmnt + + mkdir -p ${rootmnt}/halium-system + mount --move /halium-system ${rootmnt}/halium-system + + # Mounting userdata + mkdir -p ${rootmnt}/data + mkdir -p /tmpmnt/android-data + mount -o bind /tmpmnt/android-data ${rootmnt}/data + + # Set halium version properties + set_halium_version_properties ${rootmnt}/halium-system ${rootmnt}/data + + # Make sure we're booting into android's init + ln -s ../init ${rootmnt}/sbin/init + ln -s ../init ${rootmnt}/sbin/recovery + tell_kmsg "booting android..." + elif [ -e $imagefile ] || [ -n "$_syspart" ]; then + # Regular image boot + tell_kmsg "Normal boot" + + mount --move /halium-system ${rootmnt} + mkdir -p ${rootmnt}/android + + # Mounting userdata outside of /android, to avoid having LXC container access it + mkdir -p ${rootmnt}/userdata + mount --move /tmpmnt ${rootmnt}/userdata + + mount --move /android-rootfs ${rootmnt}/var/lib/lxc/android/rootfs + [ $ANDROID_IMAGE_MODE = "system" ] && mount -o rw,size=4096 -t tmpfs none ${rootmnt}/android + [ $ANDROID_IMAGE_MODE = "rootfs" ] && mount -o bind ${rootmnt}/var/lib/lxc/android/rootfs ${rootmnt}/android + + mkdir -p ${rootmnt}/android/data ${rootmnt}/android/system + + # Create a fake android data, shared by rootfs and LXC container + mkdir -p ${rootmnt}/userdata/android-data + mount -o bind ${rootmnt}/userdata/android-data ${rootmnt}/android/data + [ ! -h ${rootmnt}/data ] && ln -sf /android/data ${rootmnt}/data + + set_halium_version_properties ${rootmnt} ${rootmnt}/userdata/android-data + + # Get device information + device=$(grep ^ro.product.device= /android-system/build.prop | sed -e 's/.*=//') + [ -z "$device" ] && device="unknown" && tell_kmsg "WARNING: Didn't find a device name. Is the Android system image mounted correctly?" + tell_kmsg "device is $device" + + process_bind_mounts + + # Mount all the Android partitions + mount_android_partitions "${rootmnt}/var/lib/lxc/android/rootfs/fstab*" ${rootmnt}/android ${rootmnt}/userdata + + # system is a special case + tell_kmsg "moving Android system to /android/system" + mount --move /android-system ${rootmnt}/android/system + + # halium overlay available in the Android system image (hardware specific configs) + if [ -e ${rootmnt}/android/system/halium ]; then + mount_halium_overlay ${rootmnt}/android/system/halium ${rootmnt} + fi + + # Apply device-specific udev rules + if [ -e ${rootmnt}/usr/lib/lxc-android-config/70-$device.rules ] && + [ ! -f ${rootmnt}/android/system/halium/lib/udev/rules.d/70-android.rules ] && + [ "$device" != "unknown" ]; then + mount --bind ${rootmnt}/usr/lib/lxc-android-config/70-$device.rules ${rootmnt}/lib/udev/rules.d/70-android.rules + fi + + # Bind-mount /lib/modules from Android + mount_kernel_modules + + # Bind-mount /var/lib/ureadahead if available on persistent storage + # this is required because ureadahead runs before mountall + if [ -e ${rootmnt}/userdata/system-data/var/lib/ureadahead ] && + [ -e ${rootmnt}/var/lib/ureadahead ]; then + mount --bind ${rootmnt}/userdata/system-data/var/lib/ureadahead ${rootmnt}/var/lib/ureadahead + fi + + # Setup the swap device + [ -e ${rootmnt}/userdata/SWAP.img ] && swapon ${rootmnt}/userdata/SWAP.img + + # Apply customized content + for user in ${rootmnt}/userdata/user-data/*; do + if [ -d ${rootmnt}/custom/home ] && [ ! -e "$user/.customized" ]; then + tell_kmsg "copying custom content tp " + cp -Rap ${rootmnt}/custom/home/* "$user/" + cp -Rap ${rootmnt}/custom/home/.[a-zA-Z0-9]* "$user/" + touch "$user/.customized" + dstown=$(stat -c "%u:%g" "$user") + chown -R $dstown "$user/" + fi + done + + else + # Possibly a re-partitioned device + halium_panic "Couldn't find a system partition." + fi + + [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom" + run_scripts /scripts/local-bottom + [ "$quiet" != "y" ] && log_end_msg +}