#!/system/bin/sh # ============================================================ # WSA WebDAV Control Panel # ============================================================ # Usage: # sh app.sh Interactive menu # sh app.sh -verbose Interactive menu (verbose) # sh app.sh Direct command # sh app.sh -verbose Direct command (verbose) # # Commands: # start, stop, restart, status, health, log, config, # port, root, connections, auto-start, clear, help # ============================================================ PKG="com.wsa.webdav" DATA_DIR="/data/data/$PKG/files" RECV="$PKG/.AdbCommandReceiver" ACT_PREFIX="com.wsa.webdav" RESULT_ACT="$ACT_PREFIX.RESULT" RESULT_FILE="$DATA_DIR/result.json" CONFIG_PATH="$DATA_DIR/config.json" DEFAULT_PORT=8088 VERBOSE=0 JSON_OUT=0 # --- Colors --- c_r='\033[0;31m' c_g='\033[0;32m' c_y='\033[0;33m' c_b='\033[0;34m' c_c='\033[0;36m' c_w='\033[1;37m' c_d='\033[0m' # --- Helpers --- ok() { printf "${c_g}[OK]${c_d} %s\n" "$1"; } err() { printf "${c_r}[ERR]${c_d} %s\n" "$1"; } info() { printf "${c_c}[INFO]${c_d} %s\n" "$1"; } warn() { printf "${c_y}[WARN]${c_d} %s\n" "$1"; } vlog() { [ "$VERBOSE" -eq 1 ] && printf "${c_b}[*]${c_d} %s\n" "$1" || true; } # Extract JSON field without jq json_val() { echo "$1" | sed 's/[{}]//g' | tr ',' '\n' | grep "\"$2\"" | head -1 | sed 's/.*"'"$2"'"[[:space:]]*:[[:space:]]*//' | sed 's/[",]//g' | sed 's/^ *//;s/ *$//' } # Send broadcast command, return result from file send_cmd() { local action="$1" shift local t1=$(date +%s%N 2>/dev/null || echo 0) rm -f "$RESULT_FILE" 2>/dev/null local out out=$(am broadcast -a "$ACT_PREFIX.$action" "$@" -n "$RECV" 2>&1) local t2=$(date +%s%N 2>/dev/null || echo 0) vlog "Broadcast: $action | am output: $out" [ "$VERBOSE" -eq 1 ] && [ "$t1" != "0" ] && vlog "Time: $(( (t2 - t1) / 1000000 ))ms" sleep 0.2 if [ -f "$RESULT_FILE" ]; then local result=$(cat "$RESULT_FILE" 2>/dev/null) rm -f "$RESULT_FILE" 2>/dev/null vlog "Result: $result" echo "$result" else echo "$out" fi } # Check if port is open port_open() { local port=${1:-$DEFAULT_PORT} local hex_port=$(printf "%04X" "$port") grep -q ":${hex_port}" /proc/net/tcp /proc/net/tcp6 2>/dev/null && return 0 || return 1 } # Format uptime from ms fmt_uptime() { local ms=$1 local s=$(( ms / 1000 )) local m=$(( s / 60 )) local h=$(( m / 60 )) if [ "$h" -gt 0 ]; then echo "${h}h $(( m % 60 ))m" elif [ "$m" -gt 0 ]; then echo "${m}m $(( s % 60 ))s" else echo "${s}s" fi } get_port() { if [ -f "$CONFIG_PATH" ]; then local p=$(cat "$CONFIG_PATH" 2>/dev/null | tr -d ' \r\n' | grep -o '"port":[0-9]*' | head -1 | sed 's/"port"://') [ -n "$p" ] && [ "$p" -gt 0 ] 2>/dev/null && echo "$p" && return fi echo "$DEFAULT_PORT" } # ============================================================ # Commands # ============================================================ cmd_start() { info "Starting WebDAV server..." send_cmd "START" > /dev/null sleep 1 local port=$(get_port) if port_open "$port"; then ok "Server running on 127.0.0.1:$port" else am start -n "$PKG/.MainActivity" > /dev/null 2>&1 sleep 2 if port_open "$port"; then ok "Server running on 127.0.0.1:$port" else err "Server may not have started. Check: sh app.sh log" fi fi } cmd_stop() { info "Stopping WebDAV server..." send_cmd "STOP" > /dev/null sleep 1 ok "Stop command sent" } cmd_restart() { info "Restarting WebDAV server..." send_cmd "RESTART" > /dev/null sleep 2 local port=$(get_port) if port_open "$port"; then ok "Server restarted on 127.0.0.1:$port" else warn "Restarting... check status in a moment" fi } cmd_status() { local port=$(get_port) local running="stopped" port_open "$port" && running="running" if [ "$running" = "running" ]; then ok "Server: RUNNING" else err "Server: STOPPED" fi info "Port: $port" if [ -f "$CONFIG_PATH" ]; then local auto_start=$(grep -o '"auto_start":[^,}]*' "$CONFIG_PATH" 2>/dev/null | sed 's/.*://') [ "$auto_start" = "true" ] && info "Auto-start: ON" || info "Auto-start: OFF" fi local root_out root_out=$(send_cmd "ROOT_STATUS" 2>/dev/null) local root_avail=$(echo "$root_out" | grep -o '"root_available"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') [ "$root_avail" = "true" ] && info "Root: available" || info "Root: unavailable" } cmd_health() { info "Checking health..." local out=$(send_cmd "HEALTH" 2>/dev/null) local port_open_v=$(echo "$out" | grep -o '"port_open"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local mem_used=$(echo "$out" | grep -o '"memory_used_mb"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local mem_max=$(echo "$out" | grep -o '"memory_max_mb"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local threads=$(echo "$out" | grep -o '"threads"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local root_v=$(echo "$out" | grep -o '"root_available"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') [ "$port_open_v" = "true" ] && ok "Port: open" || err "Port: closed" info "Memory: ${mem_used}MB / ${mem_max}MB" info "Threads: $threads" [ "$root_v" = "true" ] && ok "Root: available" || info "Root: unavailable" [ "$VERBOSE" -eq 1 ] && info "Raw: $out" } cmd_log() { local lines=${1:-50} local logfile="$DATA_DIR/server.log" if [ -f "$logfile" ]; then info "Last $lines log lines:" echo "---" tail -"$lines" "$logfile" echo "---" else warn "Log file not found" fi } cmd_clear() { send_cmd "LOG_CLEAR" > /dev/null 2>&1 logcat -c 2>/dev/null ok "Logs cleared" } cmd_config() { if [ -f "$CONFIG_PATH" ]; then info "Config: $CONFIG_PATH" echo "---" cat "$CONFIG_PATH" echo "" echo "---" else warn "Config file not found at $CONFIG_PATH" info "Fetching from service..." send_cmd "CONFIG_SHOW" 2>/dev/null fi } cmd_port() { local new_port=$1 if [ -z "$new_port" ]; then local port=$(get_port) info "Current port: $port" return fi if ! [ "$new_port" -gt 0 ] 2>/dev/null; then err "Invalid port: $new_port" return fi info "Setting port to $new_port (will restart)..." send_cmd "SET_PORT" --ei port "$new_port" > /dev/null sleep 2 if port_open "$new_port"; then ok "Server running on port $new_port" else warn "Port changed, server may be restarting..." fi } cmd_root() { info "Checking root access..." local out=$(send_cmd "ROOT_STATUS" 2>/dev/null) local avail=$(echo "$out" | grep -o '"root_available"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local configured=$(echo "$out" | grep -o '"root_configured"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') [ "$avail" = "true" ] && ok "Root: available" || err "Root: unavailable" [ "$configured" = "true" ] && info "Root access: enabled" || info "Root access: disabled" if [ "$avail" != "true" ]; then info "Attempting to reacquire root..." send_cmd "REACQUIRE_ROOT" > /dev/null 2>&1 sleep 1 out=$(send_cmd "ROOT_STATUS" 2>/dev/null) avail=$(echo "$out" | grep -o '"root_available":[^,}]*' | sed 's/.*://') [ "$avail" = "true" ] && ok "Root acquired!" || warn "Root still unavailable" fi [ "$VERBOSE" -eq 1 ] && info "Raw: $out" } cmd_connections() { local out=$(send_cmd "CONNECTIONS" 2>/dev/null) local threads=$(echo "$out" | grep -o '"active_threads"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') local running=$(echo "$out" | grep -o '"server_running"[[:space:]]*:[[:space:]]*[^,}]*' | sed 's/.*://' | sed 's/[",]//g; s/^ *//;s/ *$//') [ "$running" = "true" ] && ok "Server: running" || err "Server: stopped" info "Active threads: $threads" [ "$VERBOSE" -eq 1 ] && info "Raw: $out" } cmd_autostart() { local state=$1 case "$state" in on|1|true|enable) send_cmd "ENABLE_AUTO_START" > /dev/null 2>&1 ok "Auto-start: enabled" ;; off|0|false|disable) send_cmd "DISABLE_AUTO_START" > /dev/null 2>&1 ok "Auto-start: disabled" ;; *) if [ -f "$CONFIG_PATH" ]; then local val=$(grep -o '"auto_start":[^,}]*' "$CONFIG_PATH" 2>/dev/null | sed 's/.*://') info "Auto-start: $val" fi ;; esac } cmd_help() { echo "${c_w}WSA WebDAV Control Panel${c_d}" echo "" echo "Usage: sh app.sh [-verbose] [args]" echo "" echo "Commands:" echo " start Start the WebDAV server" echo " stop Stop the server" echo " restart Restart the server" echo " status Show server status" echo " health Health check (memory, threads)" echo " log [N] Show last N log lines (default 50)" echo " clear Clear logs" echo " config Show configuration" echo " port [NNNN] Show or set port" echo " root Check root access" echo " connections Show active connections" echo " auto-start [on|off] Toggle auto-start" echo " help Show this help" echo "" echo "Flags:" echo " -verbose Verbose output" echo " -json Raw JSON output" echo "" echo "Interactive: sh app.sh (no arguments)" } # ============================================================ # Interactive Menu # ============================================================ show_menu() { echo "" echo "${c_w}+--------------------------------------+${c_d}" echo "${c_w}| WSA WebDAV Control Panel |${c_d}" echo "${c_w}+--------------------------------------+${c_d}" echo "${c_d} ${c_c}[1]${c_d} Start Server" echo "${c_d} ${c_c}[2]${c_d} Stop Server" echo "${c_d} ${c_c}[3]${c_d} Restart Server" echo "${c_d} ${c_c}[4]${c_d} Server Status" echo "${c_d} ${c_c}[5]${c_d} Health Check" echo "${c_d} ${c_c}[6]${c_d} View Logs" echo "${c_d} ${c_c}[7]${c_d} Show Config" echo "${c_d} ${c_c}[8]${c_d} Change Port" echo "${c_d} ${c_c}[9]${c_d} Root Status" echo "${c_d} ${c_c}[10]${c_d} Connections" echo "${c_d} ${c_c}[11]${c_d} Toggle Auto-Start" echo "${c_d} ${c_c}[12]${c_d} Clear Logs" echo "${c_d} ${c_c}[0]${c_d} Exit" echo "${c_w}+--------------------------------------+${c_d}" echo "" } run_menu() { while true; do show_menu printf "${c_w}Choice: ${c_d}" read choice echo "" case "$choice" in 1) cmd_start ;; 2) cmd_stop ;; 3) cmd_restart ;; 4) cmd_status ;; 5) cmd_health ;; 6) printf "Lines (default 50): " read n cmd_log "${n:-50}" ;; 7) cmd_config ;; 8) printf "New port (empty to show): " read p cmd_port "$p" ;; 9) cmd_root ;; 10) cmd_connections ;; 11) printf "Auto-start [on/off]: " read s cmd_autostart "$s" ;; 12) cmd_clear ;; 0|"") ok "Bye" exit 0 ;; *) err "Invalid choice: $choice" ;; esac echo "" printf "${c_d}Press Enter to continue..." read dummy done } # ============================================================ # Main # ============================================================ # Parse flags CMDS="" for arg in "$@"; do case "$arg" in -verbose|-v) VERBOSE=1 ;; -json|-j) JSON_OUT=1 ;; *) CMDS="$CMDS $arg" ;; esac done CMDS=$(echo "$CMDS" | xargs) # trim if [ -z "$CMDS" ]; then [ "$VERBOSE" -eq 1 ] && info "Verbose mode enabled" run_menu else # Direct command mode set -- $CMDS cmd=$1 shift case "$cmd" in start|s) cmd_start ;; stop|q) cmd_stop ;; restart|r) cmd_restart ;; status|st) cmd_status ;; health|h) cmd_health ;; log|l) cmd_log "$@" ;; clear|cl) cmd_clear ;; config|c) cmd_config ;; port|p) cmd_port "$@" ;; root|ro) cmd_root ;; connections|cn) cmd_connections ;; auto-start|as) cmd_autostart "$@" ;; help|--help|-h) cmd_help ;; *) err "Unknown command: $cmd"; cmd_help ;; esac fi