├── .gitattributes ├── script ├── README.md └── mod-util.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf 2 | script text eol=lf 3 | -------------------------------------------------------------------------------- /script: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Terminal Magisk Mod Template 3 | # by veez21 @ xda-developers 4 | 5 | 6 | # Magisk Module ID ** 7 | ID="YOUR MODULE ID" 8 | 9 | # Detect root 10 | _name=$(basename $0) 11 | ls /data >/dev/null 2>&1 || { echo "$ID needs to run as root!"; echo "type 'su' then '$_name'"; exit 1; } 12 | 13 | # Magisk Mod Directory 14 | [ -d "/sbin/.magisk" ] && MOUNTPATH="/sbin/.magisk/modules" || MOUNTPATH="$(find /dev -mindepth 2 -maxdepth 2 -type d -name ".magisk")/modules" 15 | MODDIR="$MOUNTPATH/$ID" 16 | [ ! -d $MODDIR ] && { echo "Module not detected!"; exit 1; } 17 | 18 | # Set path to your busybox if applicable 19 | _bb= 20 | 21 | # Load mod-util.sh 22 | . $MODDIR/mod-util.sh || exit $? 23 | 24 | # Set Log Files 25 | mount -o remount,rw /cache 2>/dev/null 26 | mount -o rw,remount /cache 2>/dev/null 27 | # > Logs should go in this file 28 | LOG=/data/local/tmp/$ID.log 29 | oldLOG=/data/local/tmp/$ID-old.log 30 | # > Verbose output goes here 31 | VERLOG=/data/local/tmp/$ID-verbose.log 32 | oldVERLOG=/data/local/tmp/$ID-verbose-old.log 33 | stdoutLOG=$MODDIR/logs/$ID-STDOUT.log 34 | oldstdoutLOG=$MODDIR/logs/$ID-STDOUT-old.log 35 | 36 | # Start Logging verbosely 37 | mv -f $VERLOG $oldVERLOG 2>/dev/null; mv -f $LOG $oldLOG 2>/dev/null; mv -f $stdoutLOG $oldstdoutLOG 2>/dev/null 38 | # exec 3>&1 39 | # exec 1>$stdoutLOG 40 | set -x 2>$VERLOG 41 | 42 | # Main 43 | # > You can start your MOD here. 44 | # > You can add functions, variables & etc. 45 | # > Rather than editing the default vars above. 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Terminal Emulator Magisk Module Template 2 | 3 | This template is for Making a script with visual elements which can be executed in a Terminal app in Android, **as a Magisk Module**. 4 | This provides you with useful functions that might help you easily accomplish stuff for the functions that you're making in you script. 5 | 6 | ### Magisk Modules that uses this template (you can refer to how things are used by these modules) 7 | * [Terminal Debloater](https://github.com/Magisk-Modules-Repo/terminal_debloater) 8 | * [Terminal App Systemizer](https://github.com/Magisk-Modules-Repo/terminal_systemizer) 9 | * [Fontchanger](https://github.com/Magisk-Modules-Repo/Fontchanger) 10 | * [Hidden Settings](https://github.com/Magisk-Modules-Repo/hidden_settings) 11 | * Others 12 | 13 | ### Stuff included 14 | * Root checking (if the script is running as root) 15 | * Debugging functions (to help you fix errors and bugs in your script) 16 | * Determine if the device has *A/B partitioning scheme* 17 | * Sets Busybox applets (Magisk, osm0sis') for you to not anymore call `busybox` to use them 18 | * Imports Magisk's `util_functions.sh` so that you can use the stuff in it 19 | * Gets the Device Info (Brand, Model, etc) for you to use if needed 20 | * Provides basic ANSI color codes for you to use 21 | * Useful functions and variables 22 | 23 | ### How to include in a Magisk Module (If you're not using SKIPUNZIP) 24 | 1. Place `script` (rename to anything you want) in /system/bin or xbin or anywhere you want 25 | 2. Add `mod-util.sh` in root folder of the Magisk module 26 | 3. Set the `ID` of the [script](https://github.com/veez21/mod-util/blob/69f31c10c7528463ae9a1427669939d048bf2f39/script#L7) to the `id` from your module.prop 27 | 28 | ### Functions in mod-util.sh 29 | 30 | Function | How to use | Example | Output 31 | --- | --- | --- | --- 32 | `title_div` | `title_div [-c] [character no] ` | `title_div Example` | Outputs a bar with a message: **Example ==========** 33 | `set_file_prop` | `set_file_prop ` | `set_file_prop ro.example true /cache/example.prop` | **none** 34 | `ProgressBar` | `ProgressBar ` | `ProgressBar 4 10` | Outputs a progress bar that's animated: **Progress: [==== ]** 35 | `Spinner` | `Spinner ` | `Spinner Example` | Outputs spinner loading animation **Example: [/]** (this is spinning btw) 36 | `e_spinner` | `cmd & e_spinner ` | `cmd & e_spinner Example` | Outputs spinner loading animation until the process of `cmd` is finished **Example: [/]** (this is spinning btw) 37 | `test_connection` | `test_connection` | `test_connection` | Tells you if internet's ok or not 38 | `upload_logs` | `upload_logs` | `upload_logs` | Generates termbin.com link of the logs uploaded 39 | `mod_head` | `mod_head` | `mod_head` | Outputs heading you can use in your script based on your module's `name` `id` `version` `versionCode` `author`, and also the Busybox used 40 | `prandom` | `prandom [-c] [chances] [target] ` | `prandom -c 10 7 "Hello"` | Prints message at random times (default chances=2; target=2) 41 | `pcenter` | `pcenter ` | `pcenter "Hello"` | Prints message at center alignment in terminal (work in progress) 42 | 43 | 44 | Contact me in [Telegram](https://t.me/veez21) if needed 45 | -------------------------------------------------------------------------------- /mod-util.sh: -------------------------------------------------------------------------------- 1 | ########################################################################################## 2 | # 3 | # Terminal Utility Functions 4 | # by veez21 5 | # 6 | ########################################################################################## 7 | 8 | # Versions 9 | MODUTILVER=v2.6.1 10 | MODUTILVCODE=261 11 | 12 | # Check A/B slot 13 | if [ -d /system_root ]; then 14 | isABDevice=true 15 | SYSTEM=/system_root/system 16 | SYSTEM2=/system 17 | CACHELOC=/data/cache 18 | else 19 | isABDevice=false 20 | SYSTEM=/system 21 | SYSTEM2=/system 22 | CACHELOC=/cache 23 | fi 24 | [ -z "$isABDevice" ] && { echo "Something went wrong!"; exit 1; } 25 | 26 | #=========================== Set Busybox up 27 | # Variables: 28 | # BBok - If busybox detection was ok (true/false) 29 | # _bb - Busybox binary directory 30 | # _bbname - Busybox name 31 | 32 | # set_busybox 33 | # alias busybox applets 34 | set_busybox() { 35 | if [ -x "$1" ]; then 36 | for i in $(${1} --list); do 37 | if [ "$i" != 'echo' ]; then 38 | alias "$i"="${1} $i" >/dev/null 2>&1 39 | fi 40 | done 41 | _busybox=true 42 | _bb=$1 43 | fi 44 | } 45 | _busybox=false 46 | if [ -n $_bb ]; then 47 | true 48 | elif [ -x $SYSTEM2/xbin/busybox ]; then 49 | _bb=$SYSTEM2/xbin/busybox 50 | elif [ -x $SYSTEM2/bin/busybox ]; then 51 | _bb=$SYSTEM2/bin/busybox 52 | else 53 | echo "! Busybox not detected" 54 | echo "Please install one (@osm0sis' busybox recommended)" 55 | false 56 | fi 57 | set_busybox $_bb 58 | [ $? -ne 0 ] && exit $? 59 | [ -n "$ANDROID_SOCKET_adbd" ] && alias clear='echo' 60 | _bbname="$($_bb | head -n1 | awk '{print $1,$2}')" 61 | BBok=true 62 | if [ "$_bbname" == "" ]; then 63 | _bbname="BusyBox not found!" 64 | BBok=false 65 | fi 66 | 67 | #=========================== Default Functions and Variables 68 | 69 | # Set perm 70 | set_perm() { 71 | chown $2:$3 $1 || return 1 72 | chmod $4 $1 || return 1 73 | (if [ -z $5 ]; then 74 | case $1 in 75 | *"system/vendor/app/"*) chcon 'u:object_r:vendor_app_file:s0' $1;; 76 | *"system/vendor/etc/"*) chcon 'u:object_r:vendor_configs_file:s0' $1;; 77 | *"system/vendor/overlay/"*) chcon 'u:object_r:vendor_overlay_file:s0' $1;; 78 | *"system/vendor/"*) chcon 'u:object_r:vendor_file:s0' $1;; 79 | *) chcon 'u:object_r:system_file:s0' $1;; 80 | esac 81 | else 82 | chcon $5 $1 83 | fi) || return 1 84 | } 85 | 86 | # Set perm recursive 87 | set_perm_recursive() { 88 | find $1 -type d 2>/dev/null | while read dir; do 89 | set_perm $dir $2 $3 $4 $6 90 | done 91 | find $1 -type f -o -type l 2>/dev/null | while read file; do 92 | set_perm $file $2 $3 $5 $6 93 | done 94 | } 95 | 96 | # Mktouch 97 | mktouch() { 98 | mkdir -p ${1%/*} 2>/dev/null 99 | [ -z $2 ] && touch $1 || echo $2 > $1 100 | chmod 644 $1 101 | } 102 | 103 | # Grep prop 104 | grep_prop() { 105 | local REGEX="s/^$1=//p" 106 | shift 107 | local FILES=$@ 108 | [ -z "$FILES" ] && FILES='/system/build.prop' 109 | sed -n "$REGEX" $FILES 2>/dev/null | head -n 1 110 | } 111 | 112 | # Is mounted 113 | is_mounted() { 114 | grep -q " `readlink -f $1` " /proc/mounts 2>/dev/null 115 | return $? 116 | } 117 | 118 | # Abort 119 | abort() { 120 | echo "$1" 121 | exit 1 122 | } 123 | 124 | 125 | # Device Info 126 | # Variables: BRAND MODEL DEVICE API ABI ABI2 ABILONG ARCH 127 | BRAND=$(getprop ro.product.brand) 128 | MODEL=$(getprop ro.product.model) 129 | DEVICE=$(getprop ro.product.device) 130 | ROM=$(getprop ro.build.display.id) 131 | API=$(grep_prop ro.build.version.sdk) 132 | ABI=$(grep_prop ro.product.cpu.abi | cut -c-3) 133 | ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3) 134 | ABILONG=$(grep_prop ro.product.cpu.abi) 135 | ARCH=arm 136 | ARCH32=arm 137 | IS64BIT=false 138 | if [ "$ABI" = "x86" ]; then ARCH=x86; ARCH32=x86; fi; 139 | if [ "$ABI2" = "x86" ]; then ARCH=x86; ARCH32=x86; fi; 140 | if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; ARCH32=arm; IS64BIT=true; fi; 141 | if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; ARCH32=x86; IS64BIT=true; fi; 142 | 143 | # Version Number 144 | VER=$(grep_prop version $MODDIR/module.prop) 145 | # Version Code 146 | REL=$(grep_prop versionCode $MODDIR/module.prop) 147 | # Author 148 | AUTHOR=$(grep_prop author $MODDIR/module.prop) 149 | # Mod Name/Title 150 | MODTITLE=$(grep_prop name $MODDIR/module.prop) 151 | 152 | # Colors 153 | G='\e[01;32m' # GREEN TEXT 154 | R='\e[01;31m' # RED TEXT 155 | Y='\e[01;33m' # YELLOW TEXT 156 | B='\e[01;34m' # BLUE TEXT 157 | V='\e[01;35m' # VIOLET TEXT 158 | Bl='\e[01;30m' # BLACK TEXT 159 | C='\e[01;36m' # CYAN TEXT 160 | W='\e[01;37m' # WHITE TEXT 161 | BGBL='\e[1;30;47m' # Background W Text Bl 162 | N='\e[0m' # How to use (example): echo "${G}example${N}" 163 | loadBar=' ' # Load UI 164 | # Remove color codes if -nc or in ADB Shell 165 | [ -n "$1" -a "$1" == "-nc" ] && shift && NC=true 166 | [ "$NC" -o -n "$ANDROID_SOCKET_adbd" ] && { 167 | G=''; R=''; Y=''; B=''; V=''; Bl=''; C=''; W=''; N=''; BGBL=''; loadBar='='; 168 | } 169 | 170 | # No. of characters in $MODTITLE, $VER, and $REL 171 | character_no=$(echo "$MODTITLE $VER $REL" | wc -c) 172 | 173 | # Divider 174 | div="${Bl}$(printf '%*s' "${character_no}" '' | tr " " "=")${N}" 175 | 176 | # title_div [-c] 177 | # based on $div with <title> 178 | title_div() { 179 | [ "$1" == "-c" ] && local character_no=$2 && shift 2 180 | [ -z "$1" ] && { local message=; no=0; } || { local message="$@ "; local no=$(echo "$@" | wc -c); } 181 | [ $character_no -gt $no ] && local extdiv=$((character_no-no)) || { echo "Invalid!"; return; } 182 | echo "${W}$message${N}${Bl}$(printf '%*s' "$extdiv" '' | tr " " "=")${N}" 183 | } 184 | 185 | # set_file_prop <property> <value> <prop.file> 186 | set_file_prop() { 187 | if [ -f "$3" ]; then 188 | if grep -q "$1=" "$3"; then 189 | sed -i "s/${1}=.*/${1}=${2}/g" "$3" 190 | else 191 | echo "$1=$2" >> "$3" 192 | fi 193 | else 194 | echo "$3 doesn't exist!" 195 | fi 196 | } 197 | 198 | # https://github.com/fearside/ProgressBar 199 | # ProgressBar <progress> <total> 200 | ProgressBar() { 201 | # Determine Screen Size 202 | if [[ "$COLUMNS" -le "57" ]]; then 203 | local var1=2 204 | local var2=20 205 | else 206 | local var1=4 207 | local var2=40 208 | fi 209 | # Process data 210 | local _progress=$(((${1}*100/${2}*100)/100)) 211 | local _done=$(((${_progress}*${var1})/10)) 212 | local _left=$((${var2}-$_done)) 213 | # Build progressbar string lengths 214 | local _done=$(printf "%${_done}s") 215 | local _left=$(printf "%${_left}s") 216 | 217 | # Build progressbar strings and print the ProgressBar line 218 | printf "\rProgress : ${BGBL}|${N}${_done// /${BGBL}$loadBar${N}}${_left// / }${BGBL}|${N} ${_progress}%%" 219 | } 220 | 221 | #https://github.com/fearside/SimpleProgressSpinner 222 | # Spinner <message> 223 | Spinner() { 224 | 225 | # Choose which character to show. 226 | case ${_indicator} in 227 | "|") _indicator="/";; 228 | "/") _indicator="-";; 229 | "-") _indicator="\\";; 230 | "\\") _indicator="|";; 231 | # Initiate spinner character 232 | *) _indicator="\\";; 233 | esac 234 | 235 | # Print simple progress spinner 236 | printf "\r${@} [${_indicator}]" 237 | } 238 | 239 | # cmd & spinner <message> 240 | e_spinner() { 241 | PID=$! 242 | h=0; anim='-\|/'; 243 | while [ -d /proc/$PID ]; do 244 | h=$(((h+1)%4)) 245 | sleep 0.02 246 | printf "\r${@} [${anim:$h:1}]" 247 | done 248 | } 249 | 250 | # test_connection 251 | # tests if there's internet connection 252 | test_connection() { 253 | ( 254 | if ping -q -c 1 -W 1 google.com >/dev/null 2>&1; then 255 | true 256 | elif ping -q -c 1 -W 1 baidu.com >/dev/null 2>&1; then 257 | true 258 | else 259 | false 260 | fi & e_spinner "Testing internet connection" 261 | ) && echo " - OK" || { echo " - Error"; false; } 262 | } 263 | 264 | 265 | # Log files will be uploaded to termbin.com 266 | # Logs included: VERLOG LOG oldVERLOG oldLOG 267 | upload_logs() { 268 | $BBok && { 269 | test_connection || exit 270 | echo "Uploading logs" 271 | [ -s $VERLOG ] && verUp=$(cat $VERLOG | nc termbin.com 9999) || verUp=none 272 | [ -s $oldVERLOG ] && oldverUp=$(cat $oldVERLOG | nc termbin.com 9999) || oldverUp=none 273 | [ -s $LOG ] && logUp=$(cat $LOG | nc termbin.com 9999) || logUp=none 274 | [ -s $oldLOG ] && oldlogUp=$(cat $oldLOG | nc termbin.com 9999) || oldlogUp=none 275 | [ -s $stdoutLOG ] && stdoutUp=$(cat $stdoutLOG | nc termbin.com 9999) || stdoutUp=none 276 | [ -s $oldstdoutLOG ] && oldstdoutUp=$(cat $oldstdoutLOG | nc termbin.com 9999) || oldstdoutUp=none 277 | echo -n "Link: " 278 | echo "$MODEL ($DEVICE) API $API\n$ROM\n$ID\n 279 | O_Verbose: $oldverUp 280 | Verbose: $verUp 281 | 282 | O_STDOUT: $oldstdoutUp 283 | STDOUT: $stdoutUp 284 | 285 | O_Log: $oldlogUp 286 | Log: $logUp" | nc termbin.com 9999 287 | } || echo "Busybox not found!" 288 | exit 289 | } 290 | 291 | # Print Random 292 | # Prints a message at random 293 | # CHANCES - no. of chances <integer> 294 | # TARGET - target value out of CHANCES <integer> 295 | prandom() { 296 | local CHANCES=2 297 | local TARGET=2 298 | [ "$1" == "-c" ] && { local CHANCES=$2; local TARGET=$3; shift 3; } 299 | [ "$((RANDOM%CHANCES+1))" -eq "$TARGET" ] && echo "$@" 300 | } 301 | 302 | # Print Center 303 | # Prints text in the center of terminal 304 | pcenter() { 305 | local CHAR=$(printf "$@" | sed 's|\\e[[0-9;]*m||g' | wc -m) 306 | local hfCOLUMN=$((COLUMNS/2)) 307 | local hfCHAR=$((CHAR/2)) 308 | local indent=$((hfCOLUMN-hfCHAR)) 309 | echo "$(printf '%*s' "${indent}" '') $@" 310 | } 311 | 312 | # Heading 313 | mod_head() { 314 | clear 315 | echo "$div" 316 | echo "${W}$MODTITLE $VER${N}(${Bl}$REL${N})" 317 | echo "by ${W}$AUTHOR${N}" 318 | echo "$div" 319 | echo "${W}$_bbname${N}" 320 | echo "${Bl}$_bb${N}" 321 | echo "$div" 322 | [ -s $LOG ] && echo "Enter ${W}logs${N} to upload logs" && echo $div 323 | } 324 | --------------------------------------------------------------------------------