Files
ShellCrash/scripts/menu.sh
2026-01-25 19:51:36 +08:00

392 lines
11 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# Copyright (C) Juewuy
CRASHDIR=$(
cd $(dirname $0)
pwd
)
CFG_PATH="$CRASHDIR"/configs/ShellCrash.cfg
# 加载执行目录,失败则初始化
. "$CRASHDIR"/libs/get_config.sh
[ -z "$BINDIR" -o -z "$TMPDIR" -o -z "$COMMAND" ] && . "$CRASHDIR"/init.sh >/dev/null 2>&1
[ ! -f "$TMPDIR" ] && mkdir -p "$TMPDIR"
# 通用工具
. "$CRASHDIR"/libs/set_config.sh
. "$CRASHDIR"/libs/check_cmd.sh
. "$CRASHDIR"/libs/check_autostart.sh
. "$CRASHDIR"/libs/i18n.sh
. "$CRASHDIR"/menus/common.sh
. "$CRASHDIR"/menus/1_start.sh
. "$CRASHDIR"/menus/running_status.sh
# 加载Tui界面
[ -z "$tui_type" ] && tui_type='tui_layout'
[ "$1" = '-l' ] && tui_type='tui_lite'
. "$CRASHDIR"/menus/"$tui_type".sh
# 加载语言
load_lang common
load_lang menu
checkrestart() {
line_break
separator_line "="
content_line "\033[32m$MENU_RESTART_NOTICE\033[0m"
separator_line "="
content_line "1) 立即重启"
content_line "0) 暂不重启"
separator_line "="
read -r -p "$COMMON_INPUT> " res
if [ "$res" = 1 ]; then
start_service
fi
}
# 检查端口冲突
checkport() {
while true; do
# Before each round of checks begins, execute netstat only once and cache the results
# Avoid calling the system command once for each port
current_listening=$(netstat -ntul 2>&1)
conflict_found=0
for portx in $dns_port $mix_port $redir_port $((redir_port + 1)) $db_port; do
# Use `grep` to search within the cached variables instead of re-running `netstat`
conflict_line=$(echo "$current_listening" | grep ":$portx ")
if [ -n "$conflict_line" ]; then
line_break
separator_line "="
content_line "$portx】:$MENU_PORT_CONFLICT_TITLE"
content_line "\033[0m$(echo "$conflict_line" | head -n 1)\033[0m"
content_line "\033[36m$MENU_PORT_CONFLICT_HINT\033[0m"
separator_line "="
. "$CRASHDIR"/menus/2_settings.sh && set_adv_config
. "$CRASHDIR"/libs/get_config.sh
# Mark conflict and exit the for loop, triggering the while loop to restart the check
# This replaces the original recursive call to `checkport`
conflict_found=1
break
fi
done
# If no conflicts are found after the entire for loop completes,
# the while loop exits and the function terminates.
if [ "$conflict_found" -eq 0 ]; then
break
fi
done
}
# 脚本启动前检查
ckstatus() {
versionsh=$(cat "$CRASHDIR"/version)
[ -n "$versionsh" ] && versionsh_l=$versionsh
[ -z "$redir_mod" ] && redir_mod="$MENU_PURE_MOD"
# 获取本机host地址
[ -z "$host" ] && host=$(ubus call network.interface.lan status 2>&1 | grep \"address\" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
[ -z "$host" ] && host=$(ip a 2>&1 | grep -w 'inet' | grep 'global' | grep 'lan' | grep -E ' 1(92|0|72)\.' | sed 's/.*inet.//g' | sed 's/\/[0-9][0-9].*$//g' | head -n 1)
[ -z "$host" ] && host=$(ip a 2>&1 | grep -w 'inet' | grep 'global' | grep -E ' 1(92|0|72)\.' | sed 's/.*inet.//g' | sed 's/\/[0-9][0-9].*$//g' | head -n 1)
[ -z "$host" ] && host='$MENU_IP_DF'
# dashboard目录位置
if [ -f /www/clash/index.html ]; then
dbdir=/www/clash
hostdir=/clash
else
dbdir="$CRASHDIR"/ui
hostdir=":$db_port/ui"
fi
if check_autostart; then
auto="\033[32m$MENU_AUTOSTART_ON\033[0m"
else
auto="\033[31m$MENU_AUTOSTART_OFF\033[0m"
fi
PID=$(pidof CrashCore | awk '{print $NF}')
if [ -n "$PID" ]; then
run="\033[32m$MENU_RUN_ON$redir_mod$MENU_MOD\033[0m"
running_status
elif [ "$firewall_area" = 5 ] && [ -n "$(ip route list table 100)" ]; then
run="\033[32m$MENU_RUN_SET$redir_mod$MENU_MOD\033[0m"
else
run="\033[31m$MENU_RUN_OFF$redir_mod$MENU_MOD\033[0m"
# 检测系统端口占用
checkport
fi
corename=$(echo $crashcore | sed 's/singboxr/SingBoxR/' | sed 's/singbox/SingBox/' | sed 's/clash/Clash/' | sed 's/meta/Mihomo/')
# [ "$firewall_area" = 5 ] && corename='转发'
[ -f "$TMPDIR"/debug.log -o -f "$CRASHDIR"/debug.log -a -n "$PID" ] && auto="\033[33m$MENU_AUTOSTART_DEBUG\033[0m"
# 检查新手引导
if [ -z "$userguide" ]; then
. "$CRASHDIR"/menus/userguide.sh && userguide
setconfig userguide 1
fi
# 检查执行权限
[ ! -x "$CRASHDIR"/start.sh ] && chmod +x "$CRASHDIR"/start.sh
line_break
separator_line "="
content_line " $MENU_WELCOME"
content_line ""
content_line "$(printf "%$((${TABLE_WIDTH:-60} - 1))s" "$MENU_VERSION_LABEL$versionsh_l")"
content_line " $MENU_TG_CHANNEL\033[36;4mhttps://t.me/ShellClash\033[0m"
separator_line "="
content_line "$corename$run\t $auto"
if [ -n "$PID" ]; then
content_line "$MENU_MEM_USED\033[44m$VmRSS\033[0m\t\t $MENU_RUNNING_TIME\033[46;30m$day\033[44;37m$time\033[0m"
fi
separator_line "="
# 检查/tmp内核文件
for file in $(ls /tmp | grep -v [/$] | grep -v ' ' | grep -Ev ".*(zip|7z|tar)$" | grep -iE 'CrashCore|^clash$|^clash-linux.*|^mihomo.*|^sing.*box|meta.*'); do
line_break
separator_line "="
content_line "$MENU_TMP_CORE_FOUND \033[36m/tmp/$file\033[0m"
content_line "$MENU_TMP_CORE_ASK"
separator_line "="
content_line "1) 立即加载"
content_line "0) 暂不加载"
separator_line "="
read -r -p "$COMMON_INPUT> " res
[ "$res" = 1 ] && {
line_break
separator_line "="
zip_type=$(echo "$file" | grep -oE 'tar.gz$|upx$|gz$')
. "$CRASHDIR"/menus/9_upgrade.sh && setcoretype
. "$CRASHDIR"/libs/core_tools.sh && core_check "/tmp/$file"
if [ "$?" = 0 ]; then
content_line "\033[32m$MENU_CORE_LOADED_OK\033[0m"
separator_line "="
switch_core
else
content_line "\033[33m$MENU_CORE_LOADED_BAD\033[0m"
rm -rf /tmp/"$file"
content_line "\033[33m$MENU_CORE_REMOVED\033[0m"
fi
separator_line "="
sleep 1
}
done
# 检查/tmp配置文件
for file in $(ls /tmp | grep -v [/$] | grep -v ' ' | grep -iE 'config.yaml$|config.yml$|config.json$'); do
tmp_file=/tmp/$file
line_break
separator_line "="
content_line "$MENU_TMP_CFG_FOUND \033[36m/tmp/$file\033[0m"
content_line "$MENU_TMP_CFG_ASK"
separator_line "="
content_line "1) 立即加载"
content_line "0) 暂不加载"
separator_line "="
read -p "$COMMON_INPUT> " res
[ "$res" = 1 ] && {
if [ -n "$(echo /tmp/$file | grep -iE '.json$')" ]; then
mv -f /tmp/$file "$CRASHDIR"/jsons/config.json
else
mv -f /tmp/$file "$CRASHDIR"/yamls/config.yaml
fi
line_break
separator_line "="
content_line "\033[32m$MENU_CFG_LOADED_OK\033[0m "
separator_line "="
sleep 1
}
done
# 检查禁用配置覆写
[ "$disoverride" = "1" ] && {
line_break
separator_line "="
content_line "\033[33m$MENU_OVERRIDE_WARN\033[0m"
content_line "$MENU_OVERRIDE_ASK"
separator_line "="
content_line "1) 是"
content_line "0) 否"
separator_line "="
read -p "$COMMON_INPUT> " res
[ "$res" = 1 ] && unset disoverride && setconfig disoverride
}
}
main_menu() {
while true; do
ckstatus
content_line "1) \033[32m$MENU_MAIN_1\033[0m"
content_line "2) \033[36m$MENU_MAIN_2\033[0m"
content_line "3) \033[31m$MENU_MAIN_3\033[0m"
content_line "4) \033[33m$MENU_MAIN_4\033[0m"
content_line "5) \033[32m$MENU_MAIN_5\033[0m"
content_line "6) \033[36m$MENU_MAIN_6\033[0m"
content_line "7) \033[33m$MENU_MAIN_7\033[0m"
content_line "8) $MENU_MAIN_8"
content_line "9) \033[32m$MENU_MAIN_9\033[0m"
content_line "0) $MENU_MAIN_0"
separator_line "="
read -r -p "$MENU_MAIN_PROMPT" num
case "$num" in
"" | 0)
line_break
exit 0
;;
1)
start_service
exit
line_break
;;
2)
checkcfg=$(cat "$CFG_PATH")
. "$CRASHDIR"/menus/2_settings.sh && settings
if [ -n "$PID" ]; then
checkcfg_new=$(cat "$CFG_PATH")
[ "$checkcfg" != "$checkcfg_new" ] && checkrestart
fi
;;
3)
[ "$bot_tg_service" = ON ] && . "$CRASHDIR"/menus/bot_tg_service.sh && bot_tg_stop
"$CRASHDIR"/start.sh stop
sleep 1
line_break
separator_line "="
content_line "\033[31m$corename$MENU_SERVICE_STOPPED\033[0m"
separator_line "="
sleep 1
;;
4)
. "$CRASHDIR"/menus/4_setboot.sh && setboot
;;
5)
. "$CRASHDIR"/menus/5_task.sh && task_menu
;;
6)
. "$CRASHDIR"/menus/6_core_config.sh && set_core_config
;;
7)
GT_CFG_PATH="$CRASHDIR"/configs/gateway.cfg
touch "$GT_CFG_PATH"
checkcfg=$(cat "$CFG_PATH" "$GT_CFG_PATH")
. "$CRASHDIR"/menus/7_gateway.sh && gateway
if [ -n "$PID" ]; then
checkcfg_new=$(cat "$CFG_PATH" "$GT_CFG_PATH")
[ "$checkcfg" != "$checkcfg_new" ] && checkrestart
fi
;;
8)
. "$CRASHDIR"/menus/8_tools.sh && tools
;;
9)
checkcfg=$(cat "$CFG_PATH")
. "$CRASHDIR"/menus/9_upgrade.sh && upgrade
if [ -n "$PID" ]; then
checkcfg_new=$(cat "$CFG_PATH")
[ "$checkcfg" != "$checkcfg_new" ] && checkrestart
fi
;;
*)
errornum
sleep 1
;;
esac
done
}
case "$1" in
"")
main_menu
;;
-l)
main_menu
;;
-t)
shtype=sh
[ -n "$(ls -l /bin/sh | grep -o dash)" ] && shtype=bash
"$shtype" -x "$CRASHDIR"/menu.sh -l
;;
-s)
"$CRASHDIR"/start.sh "$2" "$3" "$4" "$5" "$6"
;;
-i)
. "$CRASHDIR"/init.sh 2>/dev/null
;;
-st)
shtype=sh
ckcmd bash && shtype=bash
"$shtype" -x "$CRASHDIR"/starts/bfstart.sh
. "$CRASHDIR"/starts/start_legacy.sh
start_legacy "$COMMAND" 'shellcrash'
"$shtype" -x "$CRASHDIR"/starts/afstart.sh
"$CRASHDIR"/start.sh stop
;;
-d)
shtype=sh && [ -n "$(ls -l /bin/sh | grep -o dash)" ] && shtype=bash
line_break
separator_line "="
content_line "$MENU_TEST_RUNNING_1"
content_line "$MENU_TEST_RUNNING_2\033[36;4mhttps://t.me/ShellClash\033[0m"
separator_line "="
"$shtype" "$CRASHDIR"/start.sh debug >/dev/null 2>"$TMPDIR"/debug_sh_bug.log
"$shtype" -x "$CRASHDIR"/start.sh debug >/dev/null 2>"$TMPDIR"/debug_sh.log
line_break
cat "$TMPDIR"/debug_sh_bug.log | grep 'start\.sh' >"$TMPDIR"/sh_bug
if [ -s "$TMPDIR"/sh_bug ]; then
echo "==========================================================="
while read line; do
echo -e "$MENU_ERROR_FOUND\033[33;4m$line\033[0m"
grep -A 1 -B 3 "$line" "$TMPDIR"/debug_sh.log
echo "==========================================================="
done <"$TMPDIR"/sh_bug
rm -rf "$TMPDIR"/sh_bug
line_break
separator_line "="
content_line "\033[32m$MENU_TEST_DONE_FAIL\033[0m"
content_line "$MENU_TEST_LOG_HINT\033[36m$TMPDIR/debug_sh.log\033[0m"
separator_line "="
else
rm -rf "$TMPDIR"/debug_sh.log
separator_line "="
content_line "\033[32m$MENU_TEST_DONE_OK\033[0m"
separator_line "="
line_break
fi
"$CRASHDIR"/start.sh stop
;;
-u)
. "$CRASHDIR"/menus/uninstall.sh && uninstall
;;
*)
line_break
separator_line "="
content_line "$MENU_WELCOME"
separator_line "="
content_line "-t $MENU_CLI_TEST"
content_line "-h $MENU_CLI_HELP"
content_line "-u $MENU_CLI_UNINSTALL"
content_line "-i $MENU_CLI_INIT"
content_line "-d $MENU_CLI_DEBUG"
separator_line "-"
content_line "crash -s start $MENU_CLI_START"
content_line "crash -s stop $MENU_CLI_STOP"
content_line "$CRASHDIR/start.sh init $MENU_CLI_BOOT_INIT"
separator_line "-"
content_line "$MENU_HELP_ONLINE\033[36mhttps://t.me/ShellClash\033[0m"
content_line "$MENU_HELP_BLOG\033[36mhttps://juewuy.github.io\033[0m"
content_line "$MENU_HELP_GITHUB\033[36mhttps://github.com/juewuy/ShellCrash\033[0m"
separator_line "="
line_break
;;
esac