173 lines
5.3 KiB
Bash
Executable File
173 lines
5.3 KiB
Bash
Executable File
#!/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
|