From 4e24dc71cd3dc4997a9f669275ba2491e139c193 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Tue, 1 Aug 2023 01:04:53 +0300 Subject: [PATCH] Add RO2RW usable with any Android phone --- ro2rw | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100755 ro2rw diff --git a/ro2rw b/ro2rw new file mode 100755 index 0000000..005a3fe --- /dev/null +++ b/ro2rw @@ -0,0 +1,172 @@ +#!/system/bin/sh +# +# RO2RW for any Android phone +# +# Makes /vendor, /system and /product read-write +# And converts /system from f2fs to ext4 if it's f2fs +# +# (c) Vitaliy Filippov 2023 +# + +set -e + +resize_fs() { + local path=$1 + local label=$2 + local partname=$3 + local percent=$4 + local convert_fs=$5 + local dm_block_ext4=$(df -t ext4 | grep "$path"'$' | cut -DF1) + local dm_block_f2fs=$(df -t f2fs | grep "$path"'$' | cut -DF1) + + fs_size_mb=`du -sm $path | cut -f1` + part_size_mb=`blockdev --getsize64 $dm_block_ext4 $dm_block_f2fs | awk '{print int($1 / 1048576)}'` + super_free_mb=`lptools free | grep Free | awk '{print int($3 / 1048576)}'` + new_fs_size_mb=`echo $fs_size_mb $super_free_mb $percent | awk '{print int($1 + $2 * $3 / 100)}'` + if [[ "$new_fs_size_mb" -le "$part_size_mb" ]]; then + # just in case if we resized the partition, but not the FS + new_fs_size_mb=$part_size_mb + fi + new_fs_size=`echo $new_fs_size_mb | awk '{print $1 * 1048576}'` + + if [ "$dm_block_ext4" ]; then + echo " - Unmounting $path..." + umount $path + echo " - Resizing partition $partname inside 'super' to $new_fs_size_mb MB using lptools" + lptools resize $partname $new_fs_size + lptools unmap $partname + lptools map $partname + echo " - Checking $path block partition before resizing..." + e2fsck -f $dm_block_ext4 + echo " - Resizing the filesystem on $dm_block_ext4..." + resize2fs $dm_block_ext4 + echo " - Make the $path partition R/W by unsharing its blocks..." + e2fsck -E unshare_blocks $dm_block_ext4 + elif [ "$dm_block_f2fs" ]; then + uuid=`toybox blkid $dm_block_f2fs | egrep '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}' -o` + echo " - Create R/W $partname image..." + truncate -s ${new_fs_size_mb}M /data/new-rw.img + if [ "$convert_fs" = "ext4" ]; then + mke2fs -t ext4 -U $uuid -L $label /data/new-rw.img + else + make_f2fs -g android -O project_quota,extra_attr,inode_checksum,sb_checksum,compression,flexible_inline_xattr,verity,inode_crtime -U $uuid -f -l $label /data/new-rw.img + fi + mkdir -p /data/new-rw + mount /data/new-rw.img /data/new-rw + echo " - Copy old R/O $partname files to our new created image..." + cp -a --preserve=all $path/* /data/new-rw + # Android's toybox `cp` is buggy: `cp -a --preserve=all` does NOT preserve selinux contexts + # on directories and symlinks and you get a bootloop. So we need to restore selinux contexts... + cd $path + find . -type dl -exec ls -dZ {} \; | awk '{ print "chcon -h " $0 }' > /data/new-rw-chcon.sh + cd /data/new-rw + sh /data/new-rw-chcon.sh + cd / + umount $path + umount /data/new-rw + echo " - Checking $partname image before flashing..." + if [ "$convert_fs" = "ext4" ]; then + e2fsck -f /data/new-rw.img + else + fsck.f2fs -f /data/new-rw.img + fi + echo " - Resizing partition $partname inside 'super' to $new_fs_size_mb MB using lptools" + lptools resize $partname $(stat -c '%s' /data/new-rw.img) + lptools unmap $partname + lptools map $partname + echo " - Writing our new R/W $partname image, please wait..." + dd if=/data/new-rw.img of=/dev/block/bootdevice/by-name/$partname bs=1M + rm -rf /data/new-rw* + fi + echo " - Remounting $path..." + mount $path -o rw +} + +fs_free_size_check() { + local path=$1 + local label=$2 + local partname=$3 + local percent=$4 + echo " - Checking $path free space..." + if dd if=/dev/zero of=$path/test bs=1 count=1 2>/dev/null; then + echo " - ...succeeded." + rm -f $path/test || true + else + echo " - ...No free space on $path, attempting to resize it..." + echo " " + rm -f $path/test || true + resize_fs "$path" "$label" "$partname" "$percent" + fi +} + +echo " " +echo "RO2RW" +echo " " + +os=$(getprop ro.build.version.release) +major=${os%%.*} +dp=$(getprop ro.boot.dynamic_partitions) + +if [ $major -lt 9 ]; then + echo " - This software is incompatible with Android $major." + echo " - Installation aborted." + echo " " + exit 1 +fi + +echo " - Mounting /data..." +mount /data || true +if ! mount | grep '/data ' >/dev/null; then + echo " - Mount failed. Aborting..." + exit 3 +fi + +echo " - Mounting $ANDROID_ROOT..." +if ! mount | grep "$ANDROID_ROOT " >/dev/null; then + mount -o rw $ANDROID_ROOT 2>/dev/null || true + if ! mount | grep "$ANDROID_ROOT " >/dev/null; then + ANDROID_ROOT=/system_root + echo " - Attempt failed. Mounting at $ANDROID_ROOT..." + if ! mount | grep "$ANDROID_ROOT " >/dev/null; then + mount -o rw $ANDROID_ROOT + if ! mount | grep "$ANDROID_ROOT " >/dev/null; then + echo " - Even that attempt failed. Aborting..." + exit 2 + fi + fi + fi +fi + +echo " - Mounting /vendor..." +mount /vendor || true +mount -o remount,rw /vendor || true +if ! mount | grep '/vendor ' >/dev/null; then + echo " - Mount failed. Aborting..." + exit 3 +fi + +echo " - Mounting /product..." +mount /product || true +mount -o remount,rw /product || true +if ! mount | grep '/product ' >/dev/null; then + echo " - Mount failed. Aborting..." + exit 3 +fi + +slot=$(getprop ro.boot.slot_suffix) +fs_free_size_check $ANDROID_ROOT "/" system$slot 70 ext4 +fs_free_size_check /vendor vendor vendor$slot 50 +fs_free_size_check /product product product$slot 50 + +echo " - Unmounting /product..." +umount /product +echo " - Unmounting /vendor..." +umount /vendor +echo " - Unmounting $ANDROID_ROOT..." +umount $ANDROID_ROOT + +echo " " +echo " - Finished." +echo " " + +exit 0