Files
Wiktor a87e4b33c1 feat(settings): add comprehensive settings application script
- Introduce apply-settings.sh to apply and validate module settings
- Manage WebUI, backup, safety, system, and notification configurations
- Support automatic backup scheduling and safe mode configuration
- Include settings validation and default settings creation
- Enhance module configuration management and logging

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
2025-07-21 16:37:20 +00:00

310 lines
11 KiB
Bash
Executable File

#!/system/bin/sh
# KernelSU Anti-Bootloop & Backup Module
# boot-completed.sh - Runs after boot has completed
MODDIR=${0%/*}
MODDIR=${MODDIR%/*}
CONFIG_DIR="$MODDIR/config"
BOOTLOG_DIR="$CONFIG_DIR/boot_logs"
RECOVERY_DIR="$CONFIG_DIR/recovery_points"
SAFEMODE_DIR="$CONFIG_DIR/safe_mode"
CHECKPOINT_DIR="$CONFIG_DIR/checkpoints"
# Log function
log_message() {
echo "boot-completed: $1" >> "$MODDIR/scripts/module.log"
}
log_message "Starting boot-completed execution"
# Create boot checkpoint - final stage reached
if [ -d "$CHECKPOINT_DIR" ]; then
log_message "Creating final boot stage checkpoint"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
echo "$TIMESTAMP" > "$CHECKPOINT_DIR/boot_completed_final"
fi
# Check if we're in safe mode
is_safe_mode() {
if [ -f "$SAFEMODE_DIR/active" ] || [ -f "$CONFIG_DIR/bootloop_detected" ] || [ -f "$SAFEMODE_DIR/manual_trigger" ]; then
return 0
else
return 1
fi
}
# Reset boot counter since we successfully booted
# This is critical for the anti-bootloop protection
log_message "Boot completed successfully, resetting boot counter"
echo "0" > "$CONFIG_DIR/boot_counter"
log_message "Boot counter reset to 0 (successful boot)"
# Handle safe mode status
is_safe_mode
SAFE_MODE=$?
if [ $SAFE_MODE -eq 0 ]; then
log_message "System is in safe mode, maintaining recovery environment"
else
# Clean up any leftover safe mode indicators
if [ -f "$SAFEMODE_DIR/active" ]; then
log_message "Clearing safe mode status after successful boot"
rm -f "$SAFEMODE_DIR/active"
fi
if [ -f "$CONFIG_DIR/bootloop_detected" ]; then
log_message "Clearing bootloop detection flag after successful boot"
rm -f "$CONFIG_DIR/bootloop_detected"
fi
if [ -f "$SAFEMODE_DIR/manual_trigger" ]; then
log_message "Clearing manual safe mode trigger after successful boot"
rm -f "$SAFEMODE_DIR/manual_trigger"
fi
fi
# Create a boot success marker
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
echo "Boot completed successfully at $TIMESTAMP" > "$MODDIR/config/boot_logs/boot_success_${TIMESTAMP}.log"
# System verification
verify_system() {
log_message "Verifying system integrity"
# Check critical system services
ZYGOTE_RUNNING=$(ps -A | grep zygote | wc -l)
SYSTEM_SERVER_RUNNING=$(ps -A | grep system_server | wc -l)
if [ "$ZYGOTE_RUNNING" -gt 0 ] && [ "$SYSTEM_SERVER_RUNNING" -gt 0 ]; then
log_message "Core system services are running"
return 0
else
log_message "Warning: Some core system services may not be running properly"
return 1
fi
}
# Create recovery point after successful boot
create_recovery_point() {
log_message "Creating successful boot recovery point"
# Get total recovery points
RECOVERY_COUNT=$(ls -1 "$RECOVERY_DIR" 2>/dev/null | wc -l)
# Only create new recovery point if we have less than 3
# This prevents filling up storage with too many recovery points
if [ "$RECOVERY_COUNT" -lt 3 ]; then
RECOVERY_POINT_DIR="$RECOVERY_DIR/recovery_${TIMESTAMP}"
mkdir -p "$RECOVERY_POINT_DIR"
# Log recovery point information
echo "Recovery point created at: $(date)" > "$RECOVERY_POINT_DIR/info.txt"
echo "Android version: $(getprop ro.build.version.release)" >> "$RECOVERY_POINT_DIR/info.txt"
echo "Device: $(getprop ro.product.model)" >> "$RECOVERY_POINT_DIR/info.txt"
echo "KernelSU version: $(cat /data/adb/ksu/version 2>/dev/null || echo "Unknown")" >> "$RECOVERY_POINT_DIR/info.txt"
# Create list of active modules
mkdir -p "$RECOVERY_POINT_DIR/modules"
if [ -d "/data/adb/modules" ]; then
ls -la /data/adb/modules/ > "$RECOVERY_POINT_DIR/modules/list.txt"
# Save modules state
for MODULE_DIR in /data/adb/modules/*; do
if [ -d "$MODULE_DIR" ]; then
MODULE_NAME=$(basename "$MODULE_DIR")
mkdir -p "$RECOVERY_POINT_DIR/modules/$MODULE_NAME"
# Save module properties
if [ -f "$MODULE_DIR/module.prop" ]; then
cp "$MODULE_DIR/module.prop" "$RECOVERY_POINT_DIR/modules/$MODULE_NAME/"
fi
# Check if module is disabled
if [ -f "$MODULE_DIR/disable" ]; then
touch "$RECOVERY_POINT_DIR/modules/$MODULE_NAME/disable"
fi
# Check module state
if [ -f "$MODULE_DIR/remove" ]; then
touch "$RECOVERY_POINT_DIR/modules/$MODULE_NAME/remove"
fi
fi
done
fi
# Save system properties
mkdir -p "$RECOVERY_POINT_DIR/system"
getprop > "$RECOVERY_POINT_DIR/system/properties.txt"
# Save loaded kernel modules
lsmod > "$RECOVERY_POINT_DIR/system/kernel_modules.txt" 2>/dev/null
# Save mount points
mount > "$RECOVERY_POINT_DIR/system/mounts.txt"
# Create restore script for this recovery point
cat > "$RECOVERY_POINT_DIR/restore.sh" << EOF
#!/system/bin/sh
# Auto-generated restore script for recovery point $TIMESTAMP
MODDIR=\${0%/*}
MODDIR=\${MODDIR%/*}
MODDIR=\${MODDIR%/*}
# Log function
log_message() {
echo "[\$(date)] restore: \$1" >> "\$MODDIR/scripts/module.log"
}
log_message "Restoring from recovery point $TIMESTAMP"
# Disable all modules first
if [ -d "/data/adb/modules" ]; then
for MODULE in /data/adb/modules/*; do
if [ -d "\$MODULE" ] && [ ! -f "\$MODULE/disable" ]; then
MODULE_NAME=\$(basename "\$MODULE")
log_message "Disabling module \$MODULE_NAME"
touch "\$MODULE/disable"
fi
done
fi
# Re-enable modules that were active in recovery point
for MODULE_DIR in "\$MODDIR/config/recovery_points/recovery_${TIMESTAMP}/modules/"*; do
if [ -d "\$MODULE_DIR" ] && [ ! -f "\$MODULE_DIR/disable" ]; then
MODULE_NAME=\$(basename "\$MODULE_DIR")
if [ -d "/data/adb/modules/\$MODULE_NAME" ]; then
log_message "Re-enabling module \$MODULE_NAME"
rm -f "/data/adb/modules/\$MODULE_NAME/disable"
fi
fi
done
log_message "Recovery completed"
EOF
# Make restore script executable
chmod +x "$RECOVERY_POINT_DIR/restore.sh"
log_message "Recovery point created: $RECOVERY_POINT_DIR"
else
log_message "Maximum recovery points reached, removing oldest and creating new one"
# Remove oldest recovery point
OLDEST_POINT=$(ls -1t "$RECOVERY_DIR" | tail -1)
if [ ! -z "$OLDEST_POINT" ]; then
log_message "Removing oldest recovery point: $OLDEST_POINT"
rm -rf "$RECOVERY_DIR/$OLDEST_POINT"
# Now create the new recovery point (recursive call)
create_recovery_point
fi
fi
}
# Clean up old logs
cleanup_old_logs() {
log_message "Cleaning up old logs"
# Keep only the 10 most recent boot logs
if [ -d "$MODDIR/config/boot_logs" ]; then
LOGS_TO_DELETE=$(ls -1t "$MODDIR/config/boot_logs" | tail -n +11)
if [ ! -z "$LOGS_TO_DELETE" ]; then
for LOG in $LOGS_TO_DELETE; do
rm -f "$MODDIR/config/boot_logs/$LOG"
done
log_message "Deleted $(echo "$LOGS_TO_DELETE" | wc -l) old boot logs"
fi
fi
# Limit main log file size
if [ -f "$MODDIR/scripts/module.log" ] && [ $(stat -c%s "$MODDIR/scripts/module.log") -gt 1048576 ]; then
# If log is larger than 1MB, keep only the last 1000 lines
tail -n 1000 "$MODDIR/scripts/module.log" > "$MODDIR/scripts/module.log.new"
mv "$MODDIR/scripts/module.log.new" "$MODDIR/scripts/module.log"
log_message "Trimmed module.log to last 1000 lines"
fi
}
# Display boot notification (if device is unlocked)
show_boot_notification() {
log_message "Attempting to show boot notification"
# Check if device is unlocked
SCREEN_STATE=$(dumpsys power | grep "mHoldingDisplaySuspendBlocker" | grep "true" | wc -l)
if [ "$SCREEN_STATE" -gt 0 ]; then
# Device screen is on, try to show notification
am start -a android.intent.action.VIEW -d "http://localhost:8080" >/dev/null 2>&1
log_message "Boot notification displayed"
else
log_message "Screen is off, skipping boot notification"
fi
}
# Clear pending transaction if any
clear_pending_transactions() {
if [ -d "$CONFIG_DIR/transactions" ] && [ -f "$CONFIG_DIR/transactions/current" ]; then
TRANSACTION_ID=$(cat "$CONFIG_DIR/transactions/current" 2>/dev/null)
if [ ! -z "$TRANSACTION_ID" ]; then
log_message "Committing pending transaction: $TRANSACTION_ID"
# Source overlayfs script to get access to commit function
if [ -f "$MODDIR/scripts/overlayfs.sh" ]; then
. "$MODDIR/scripts/overlayfs.sh"
commit_transaction "$TRANSACTION_ID"
else
# Simple fallback if script not available
echo "2" > "$CONFIG_DIR/transactions/$TRANSACTION_ID/state"
rm -f "$CONFIG_DIR/transactions/current"
fi
fi
fi
}
# Main function
main() {
# Verify system integrity
verify_system
# Create recovery point only if not in safe mode
is_safe_mode
SAFE_MODE=$?
if [ $SAFE_MODE -eq 0 ]; then
log_message "System in safe mode, skipping recovery point creation"
else
# Create recovery point after successful boot
create_recovery_point
# Clear any pending transactions
clear_pending_transactions
fi
# Clean up old logs
cleanup_old_logs
# Wait a moment to ensure system is fully initialized
sleep 5
# Show boot notification if appropriate
is_safe_mode
SAFE_MODE=$?
if [ $SAFE_MODE -eq 0 ]; then
# In safe mode, show recovery notification
show_boot_notification
else
# Normal boot, show regular notification if configured
SHOW_NOTIFICATIONS=$(grep "show_notifications" "$CONFIG_DIR/main.conf" | cut -d= -f2 || echo "false")
if [ "$SHOW_NOTIFICATIONS" = "true" ]; then
show_boot_notification
fi
fi
# Record system stats
log_message "System memory: $(free | grep Mem | awk '{print $3"/"$2" used"}')"
log_message "System uptime: $(uptime)"
log_message "Boot completed successfully!"
return 0
}
# Execute main function
main