diff --git a/build.py b/build.py index 5aafa6d1c..142614e06 100755 --- a/build.py +++ b/build.py @@ -219,6 +219,10 @@ def zip_uninstaller(args): target = 'magisk_uninstaller.sh' zip_with_msg(zipf, source, target) + source = os.path.join('scripts', 'util_functions.sh') + target = 'util_functions.sh' + zip_with_msg(zipf, source, target) + source = os.path.join('scripts', 'uninstaller_loader.sh') target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary') zip_with_msg(zipf, source, target) @@ -227,6 +231,13 @@ def zip_uninstaller(args): print('zip: ' + target) zipf.writestr(target, '#MAGISK\n') + # Prebuilts + for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']: + source = os.path.join('chromeos', chromeos) + zip_with_msg(zipf, source, source) + + # End of zipping + output = 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d')) sign_adjust_zip('tmp_unsigned.zip', output) diff --git a/scripts/addon.d.sh b/scripts/addon.d.sh index 8c33f09c9..255e58d84 100644 --- a/scripts/addon.d.sh +++ b/scripts/addon.d.sh @@ -28,7 +28,7 @@ main() { mount -o ro /vendor 2>/dev/null mount /data 2>/dev/null - # Load all functions + # Load utility functions . $MAGISKBIN/util_functions.sh [ -f /system/build.prop ] || abort "! /system could not be mounted!" @@ -57,7 +57,7 @@ main() { if [ -L "$BOOTIMAGE" ]; then dd if=new-boot.img of="$BOOTIMAGE" bs=4096 else - cat new-boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 + cat new-boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 >/dev/null 2>&1 fi rm -f new-boot.img diff --git a/scripts/boot_patch.sh b/scripts/boot_patch.sh index ca974d949..d91a07edf 100644 --- a/scripts/boot_patch.sh +++ b/scripts/boot_patch.sh @@ -4,7 +4,7 @@ # Magisk Boot Image Patcher # by topjohnwu # -# This script should be placed in a directory with at least the following files: +# This script should be placed in a directory with the following files: # # File name type Description # @@ -14,9 +14,11 @@ # magisk binary The main binary for all Magisk operations. # It is also used to patch the sepolicy in the ramdisk. # magiskboot binary A tool to unpack boot image, decompress ramdisk, extract ramdisk -# and patch common patches such as forceencrypt, remove dm-verity. +# , and patch the ramdisk for Magisk support # init.magisk.rc script A new line will be added to init.rc to import this script. # All magisk entrypoints are defined here +# chromeos folder This folder should store all the utilities and keys to sign +# (optional) a chromeos device, used in the tablet Pixel C # # If the script is not running as root, then the input boot image should be a stock image # or have a backup included in ramdisk internally, since we cannot access the stock boot @@ -231,4 +233,16 @@ A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054 ui_print_wrap "- Repacking boot image" ./magiskboot --repack "$BOOTIMAGE" || abort_wrap "! Unable to repack boot image!" +# Sign chromeos boot +if [ -f chromeos ]; then + echo > empty + + ./chromeos/futility vbutil_kernel --pack new-boot.img.signed \ + --keyblock ./chromeos/kernel.keyblock --signprivate ./chromeos/kernel_data_key.vbprivk \ + --version 1 --vmlinuz new-boot.img --config empty --arch arm --bootloader empty --flags 0x1 + + rm -f empty new-boot.img + mv new-boot.img.signed new-boot.img +fi + ./magiskboot --cleanup diff --git a/scripts/flash_script.sh b/scripts/flash_script.sh index 430fa6623..ccf68f42b 100644 --- a/scripts/flash_script.sh +++ b/scripts/flash_script.sh @@ -9,6 +9,10 @@ # ########################################################################################## +########################################################################################## +# Preparation +########################################################################################## + # Detect whether in boot mode ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true || BOOTMODE=false $BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && BOOTMODE=true @@ -16,7 +20,7 @@ $BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && BOOTMO # This path should work in any cases TMPDIR=/dev/tmp -INSTALLER=$TMPDIR/magisk +INSTALLER=$TMPDIR/install COMMONDIR=$INSTALLER/common CHROMEDIR=$INSTALLER/chromeos COREDIR=/magisk/.core @@ -24,45 +28,27 @@ COREDIR=/magisk/.core # Default permissions umask 022 -########################################################################################## -# Flashable update-binary preparation -########################################################################################## - OUTFD=$2 ZIP=$3 -readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null -if [ "$?" -eq "0" ]; then - OUTFD=0 - - for FD in `ls /proc/$$/fd`; do - readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null - if [ "$?" -eq "0" ]; then - ps | grep " 3 $FD " | grep -v grep >/dev/null - if [ "$?" -eq "0" ]; then - OUTFD=$FD - break - fi - fi - done -fi - rm -rf $TMPDIR 2>/dev/null mkdir -p $INSTALLER -unzip -o "$ZIP" -d $INSTALLER - -########################################################################################## -# Detection -########################################################################################## +unzip -o "$ZIP" -d $INSTALLER 2>/dev/null if [ ! -d "$COMMONDIR" ]; then echo "! Unable to extract zip file!" exit 1 fi -# Load all fuctions +# Load utility fuctions . $COMMONDIR/util_functions.sh +get_outfd + +########################################################################################## +# Detection +########################################################################################## + ui_print "************************" ui_print "* MAGISK_VERSION_STUB" ui_print "************************" @@ -108,6 +94,7 @@ is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin rm -rf $MAGISKBIN 2>/dev/null mkdir -p $MAGISKBIN cp -af $BINDIR/. $COMMONDIR/. $MAGISKBIN +cp -af $CHROMEDIR $MAGISKBIN chmod -R 755 $MAGISKBIN # addon.d @@ -125,7 +112,7 @@ fi $BOOTMODE || recovery_actions # Fix SuperSU..... -$BOOTMODE && $BINDIR/magisk magiskpolicy --live "allow fsck * * *" +$BOOTMODE && $MAGISKBIN/magisk magiskpolicy --live "allow fsck * * *" if (is_mounted /data); then IMG=/data/magisk.img @@ -138,12 +125,12 @@ if [ -f $IMG ]; then ui_print "- $IMG detected!" else ui_print "- Creating $IMG" - $BINDIR/magisk --createimg $IMG 64M + $MAGISKBIN/magisk --createimg $IMG 64M fi if ! is_mounted /magisk; then ui_print "- Mounting $IMG to /magisk" - MAGISKLOOP=`$BINDIR/magisk --mountimg $IMG /magisk` + MAGISKLOOP=`$MAGISKBIN/magisk --mountimg $IMG /magisk` fi is_mounted /magisk || abort "! Magisk image mount failed..." @@ -165,10 +152,10 @@ ui_print "- Found Boot Image: $BOOTIMAGE" # Update our previous backup to new format if exists if [ -f /data/stock_boot.img ]; then - SHA1=`$BINDIR/magiskboot --sha1 /data/stock_boot.img | tail -n 1` + SHA1=`$MAGISKBIN/magiskboot --sha1 /data/stock_boot.img | tail -n 1` STOCKDUMP=/data/stock_boot_${SHA1}.img mv /data/stock_boot.img $STOCKDUMP - $BINDIR/magiskboot --compress $STOCKDUMP + $MAGISKBIN/magiskboot --compress $STOCKDUMP fi SOURCEDMODE=true @@ -177,20 +164,11 @@ cd $MAGISKBIN # Source the boot patcher . $COMMONDIR/boot_patch.sh "$BOOTIMAGE" -# Sign chromeos boot -if [ -f chromeos ]; then - echo > empty - - $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed \ - --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk \ - --version 1 --vmlinuz new-boot.img --config empty --arch arm --bootloader empty --flags 0x1 - - rm -f empty new-boot.img - mv new-boot.img.signed new-boot.img +if [ -f stock_boot* ]; then + rm -f /data/stock_boot* 2>/dev/null + mv stock_boot* /data fi -[ -f stock_boot* ] && rm -f /data/stock_boot* 2>/dev/null - ui_print "- Flashing new boot image" if [ -L "$BOOTIMAGE" ]; then dd if=new-boot.img of="$BOOTIMAGE" bs=4096 @@ -202,7 +180,7 @@ rm -f new-boot.img cd / if ! $BOOTMODE; then - $BINDIR/magisk --umountimg /magisk $MAGISKLOOP + $MAGISKBIN/magisk --umountimg /magisk $MAGISKLOOP rmdir /magisk recovery_cleanup fi diff --git a/scripts/magisk_uninstaller.sh b/scripts/magisk_uninstaller.sh index ebcc089e5..3f39de52e 100644 --- a/scripts/magisk_uninstaller.sh +++ b/scripts/magisk_uninstaller.sh @@ -8,120 +8,103 @@ # The Magisk main binary will pick up the script, and uninstall itself, following a reboot # This script can also be used in flashable zip with the uninstaller_loader.sh # -# This script will try to do restoration in the following order: -# 1. Find and restore the original stock boot image dump (OTA proof) -# 2. Restore ramdisk from the internal backup (ramdisk fully restored, not OTA friendly) -# 3. Remove added files in ramdisk, modified files are remained intact. By doing so, Magisk -# will not be started at boot, but not removed clean enough -# -# Finally, this uninstaller will remove all Magisk related files -# (The list is LARGE, most likely due to bad decision in early versions -# the latest versions has much less bloat to cleanup) +# This script will try to do restoration with the following: +# 1-1. Find and restore the original stock boot image dump (OTA proof) +# 1-2. If 1-1 fails, restore ramdisk from the internal backup +# (ramdisk fully restored, not OTA friendly) +# 1-3. If 1-2 fails, it will remove added files in ramdisk, however modified files +# are remained modified, because we have no backups. By doing so, Magisk will +# not be started at boot, but this isn't actually 100% cleaned up +# 2. Remove all Magisk related files +# (The list is LARGE, most likely due to bad decision in early versions +# the latest versions has much less bloat to cleanup) # ########################################################################################## - -[ -z $BOOTMODE ] && BOOTMODE=false - -MAGISKBIN=/data/magisk -CHROMEDIR=$MAGISKBIN/chromeos - -[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64 || SYSTEMLIB=/system/lib - -# Default permissions -umask 022 - # Call ui_print_wrap if exists, or else simply use echo # Useful when wrapped in flashable zip ui_print_wrap() { type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1" } -grep_prop() { - REGEX="s/^$1=//p" - shift - FILES=$@ - if [ -z "$FILES" ]; then - FILES='/system/build.prop' - fi - cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1 -} - -find_boot_image() { - if [ -z "$BOOTIMAGE" ]; then - for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do - BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION` - if [ ! -z "$BOOTIMAGE" ]; then break; fi - done - fi - if [ -z "$BOOTIMAGE" ]; then - FSTAB="/etc/recovery.fstab" - [ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak" - [ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'` +# Call abort if exists, or else show error message and exit +# Essential when wrapped in flashable zip +abort_wrap() { + type abort >/dev/null 2>&1 + if [ $? -ne 0 ]; then + ui_print_wrap "$1" + exit 1 + else + abort "$1" fi } -# Environments -# Set permissions -chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null +if [ ! -d $MAGISKBIN -o ! -f $MAGISKBIN/magiskboot -o ! -f $MAGISKBIN/util_functions.sh ]; then + ui_print_wrap "! Cannot find $MAGISKBIN" + exit 1 +fi + +[ -z $BOOTMODE ] && BOOTMODE=false + +MAGISKBIN=/data/magisk +CHROMEDIR=$MAGISKBIN/chromeos + +# Default permissions +umask 022 + +# Load utility functions +. $MAGISKBIN/util_functions.sh # Find the boot image find_boot_image -if [ -z "$BOOTIMAGE" ]; then - ui_print_wrap "! Unable to detect boot image" - exit 1 -fi +[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image" ui_print_wrap "- Found Boot Image: $BOOTIMAGE" cd $MAGISKBIN ui_print_wrap "- Unpacking boot image" -LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --unpack $BOOTIMAGE -if [ $? -ne 0 ]; then - ui_print_wrap "! Unable to unpack boot image" - exit 1 -fi +./magiskboot --unpack "$BOOTIMAGE" +[ $? -ne 0 ] && abort_wrap "! Unable to unpack boot image" -# Update our previous backups to new format if exists +# Update our previous backup to new format if exists if [ -f /data/stock_boot.img ]; then - SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --sha1 /data/stock_boot.img | tail -n 1` + SHA1=`./magiskboot --sha1 /data/stock_boot.img | tail -n 1` STOCKDUMP=/data/stock_boot_${SHA1}.img mv /data/stock_boot.img $STOCKDUMP - LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --compress $STOCKDUMP + ./magiskboot --compress $STOCKDUMP fi # Detect boot image state -LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-test ramdisk.cpio +./magiskboot --cpio-test ramdisk.cpio case $? in - 0 ) + 0 ) # Stock boot ui_print_wrap "- Stock boot image detected!" ui_print_wrap "! Magisk is not installed!" exit ;; - 1 ) + 1 ) # Magisk patched ui_print_wrap "- Magisk patched image detected!" # Find SHA1 of stock boot image if [ -z $SHA1 ]; then - LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old + ./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old` - [ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img rm -f init.magisk.rc.old fi + [ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img if [ -f ${STOCKDUMP}.gz ]; then ui_print_wrap "- Boot image backup found!" - LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img + ./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img else ui_print_wrap "! Boot image backup unavailable" ui_print_wrap "- Restoring ramdisk with backup" - LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-restore ramdisk.cpio - LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --repack $BOOTIMAGE stock_boot.img + ./magiskboot --cpio-restore ramdisk.cpio + ./magiskboot --repack $BOOTIMAGE stock_boot.img fi ;; 2 ) # Other patched - ui_print_wrap "! Boot image patched by other programs!" - ui_print_wrap "! Cannot uninstall with this uninstaller" - exit 1 + ui_print_wrap "! Boot image patched by other programs!" + abort_wrap "! Cannot uninstall with this uninstaller" ;; esac @@ -138,10 +121,10 @@ if [ -f chromeos ]; then fi ui_print_wrap "- Flashing stock/reverted image" -if [ -L $BOOTIMAGE ]; then - dd if=stock_boot.img of=$BOOTIMAGE bs=4096 +if [ -L "$BOOTIMAGE" ]; then + dd if=stock_boot.img of="$BOOTIMAGE" bs=4096 else - cat stock_boot.img /dev/zero | dd of=$BOOTIMAGE bs=4096 + cat stock_boot.img /dev/zero | dd of="$BOOTIMAGE" bs=4096 >/dev/null 2>&1 fi rm -f stock_boot.img diff --git a/scripts/uninstaller_loader.sh b/scripts/uninstaller_loader.sh index 95ff4a1cc..aba2338f9 100644 --- a/scripts/uninstaller_loader.sh +++ b/scripts/uninstaller_loader.sh @@ -8,100 +8,49 @@ # ########################################################################################## -INSTALLER=/tmp/uninstall +########################################################################################## +# Preparation +########################################################################################## +BOOTMODE=false +INSTALLER=/tmp/uninstall # Default permissions umask 022 -########################################################################################## -# Flashable update-binary preparation -########################################################################################## - OUTFD=$2 ZIP=$3 -readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null -if [ "$?" -eq "0" ]; then - OUTFD=0 +rm -rf $INSTALLER 2>/dev/null +mkdir -p $INSTALLER +unzip -o "$ZIP" -d $INSTALLER 2>/dev/null - for FD in `ls /proc/$$/fd`; do - readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null - if [ "$?" -eq "0" ]; then - ps | grep " 3 $FD " | grep -v grep >/dev/null - if [ "$?" -eq "0" ]; then - OUTFD=$FD - break - fi - fi - done +if [ ! -f $INSTALLER/util_functions.sh ]; then + echo "! Failed: Unable to extract zip file!" + exit 1 fi -mkdir -p $INSTALLER -cd $INSTALLER -unzip -o "$ZIP" +# Load utility functions +. $INSTALLER/util_functions.sh -########################################################################################## -# Functions -########################################################################################## - -ui_print() { - echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD - echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD -} - -is_mounted() { - if [ ! -z "$2" ]; then - cat /proc/mounts | grep $1 | grep $2, >/dev/null - else - cat /proc/mounts | grep $1 >/dev/null - fi - return $? -} - -grep_prop() { - REGEX="s/^$1=//p" - shift - FILES=$@ - if [ -z "$FILES" ]; then - FILES='/system/build.prop' - fi - cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1 -} +get_outfd ########################################################################################## # Main ########################################################################################## -ui_print "*****************************" -ui_print " Magisk Uninstaller " -ui_print "*****************************" +ui_print "************************" +ui_print " Magisk Uninstaller " +ui_print "************************" -if [ ! -d "$INSTALLER/arm" ]; then - ui_print "! Failed: Unable to extract zip file!" - exit 1 -fi - -ui_print "- Mounting /system(ro), /cache, /data" +ui_print "- Mounting /system, /vendor, /cache, /data" mount -o ro /system 2>/dev/null +mount -o ro /vendor 2>/dev/null mount /cache 2>/dev/null mount /data 2>/dev/null -if [ ! -f '/system/build.prop' ]; then - ui_print "! Failed: /system could not be mounted!" - exit 1 -fi +[ -f /system/build.prop ] || abort "! /system could not be mounted!" -API=`grep_prop ro.build.version.sdk` -ABI=`grep_prop ro.product.cpu.abi | cut -c-3` -ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3` -ABILONG=`grep_prop ro.product.cpu.abi` - -ARCH=arm -IS64BIT=false -if [ "$ABI" = "x86" ]; then ARCH=x86; fi; -if [ "$ABI2" = "x86" ]; then ARCH=x86; fi; -if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi; -if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi; +api_level_arch_detect ui_print "- Device platform: $ARCH" CHROMEDIR=$INSTALLER/chromeos @@ -111,12 +60,20 @@ BINDIR=$INSTALLER/$ARCH # Detection all done, start installing ########################################################################################## -if (is_mounted /data); then +MAGISKBIN=/data/magisk + +if is_mounted /data; then # Copy the binaries to /data/magisk, in case they do not exist - rm -rf /data/magisk 2>/dev/null - mkdir -p /data/magisk 2>/dev/null - cp -af $BINDIR/. $CHROMEDIR /data/magisk + rm -rf $MAGISKBIN 2>/dev/null + mkdir -p $MAGISKBIN + cp -af $BINDIR/. $MAGISKBIN + cp -af $CHROMEDIR $MAGISKBIN + cp -af $INSTALLER/util_functions.sh $MAGISKBIN + chmod -R 755 $MAGISKBIN + # Run the acttual uninstallation + recovery_actions . $INSTALLER/magisk_uninstaller.sh + recovery_cleanup else ui_print "! Data unavailable" ui_print "! Placing uninstall script to /cache" @@ -128,6 +85,5 @@ else reboot fi -umount /system ui_print "- Done" exit 0 diff --git a/scripts/util_functions.sh b/scripts/util_functions.sh index e26d4c3b4..b113bd9bf 100644 --- a/scripts/util_functions.sh +++ b/scripts/util_functions.sh @@ -3,10 +3,28 @@ # Magisk General Utility Functions # by topjohnwu # -# Used in flash_script.sh and addon.d.sh +# Used in flash_script.sh, addon.d.sh, magisk module installers, and uninstaller # ########################################################################################## +get_outfd() { + readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null + if [ "$?" -eq "0" ]; then + OUTFD=0 + + for FD in `ls /proc/$$/fd`; do + readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null + if [ "$?" -eq "0" ]; then + ps | grep " 3 $FD " | grep -v grep >/dev/null + if [ "$?" -eq "0" ]; then + OUTFD=$FD + break + fi + fi + done + fi +} + ui_print() { if $BOOTMODE; then echo "$1" @@ -130,3 +148,45 @@ abort() { mv /sbin_tmp /sbin 2>/dev/null exit 1 } + +set_perm() { + chown $2:$3 $1 || exit 1 + chmod $4 $1 || exit 1 + if [ ! -z $5 ]; then + chcon $5 $1 2>/dev/null + else + chcon 'u:object_r:system_file:s0' $1 2>/dev/null + fi +} + +set_perm_recursive() { + find $1 -type d 2>/dev/null | while read dir; do + set_perm $dir $2 $3 $4 $6 + done + find $1 -type f 2>/dev/null | while read file; do + set_perm $file $2 $3 $5 $6 + done +} + +mktouch() { + mkdir -p ${1%/*} + if [ -z "$2" ]; then + touch $1 + else + echo $2 > $1 + fi + chmod 644 $1 +} + +request_size_check() { + reqSizeM=`du -s $1 | cut -f1` + reqSizeM=$((reqSizeM / 1024 + 1)) +} + +image_size_check() { + SIZE="`$MAGISKBIN/magisk --imgsize $IMG`" + curUsedM=`echo "$SIZE" | cut -d" " -f1` + curSizeM=`echo "$SIZE" | cut -d" " -f2` + curFreeM=$((curSizeM - curUsedM)) +} +