🎨 Sync 2026-10-09 01:04:17

This commit is contained in:
github-actions[bot] committed 2026-10-09 01:04:17 +08:00
1 parent eb76e89012
commit 812da7f08b
154 files changed
+10613 -3987

No files matched your search

@@ -1,35 +1,39 @@
#!/bin/sh
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifupdate" ] || exit 0
[ -n "$DEVICE" ] || exit 0
. /usr/share/passwall/utils.sh
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifupdate" ] || exit 0
[ -f "${LOCK_PATH}/${CONFIG}_ready.lock" ] || exit 0
[ "$(get_cache_var "ENABLED_DEFAULT_ACL")" = "1" ] || [ "$(get_cache_var "ENABLED_ACLS")" = "1" ] || exit 0
([ "$(get_cache_var "ENABLED_DEFAULT_ACL")" = "1" ] || [ "$(get_cache_var "ENABLED_ACLS")" = "1" ]) && [ -f ${LOCK_PATH}/${CONFIG}_ready.lock ] && {
default_device=$(ip route show default 2>/dev/null | awk '{ for (i = 1; i < NF; i++) if ($i == "dev") { print $(i + 1); break } exit }')
default6_device=$(ip -6 route show default 2>/dev/null | awk '{ for (i = 1; i < NF; i++) if ($i == "dev") { print $(i + 1); break } exit }')
[ "$default_device" = "$DEVICE" ] || [ "$default6_device" = "$DEVICE" ] || exit 0
default_device=$(ip route show default 2>/dev/null | awk -F 'dev ' '{print $2}' | awk '{print $1}' | head -n1)
default6_device=$(ip -6 route show default 2>/dev/null | awk -F 'dev ' '{print $2}' | awk '{print $1}' | head -n1)
( [ "$default_device" = "$DEVICE" ] || [ "$default6_device" = "$DEVICE" ] ) && {
if [ "$ACTION" = "ifupdate" ]; then
USE_TABLES=$(get_cache_var "USE_TABLES")
[ -n "$USE_TABLES" ] && { "${APP_PATH}/${USE_TABLES}.sh" update_wan_sets >/dev/null 2>&1 & }
exit 0
fi
if [ "$ACTION" = "ifupdate" ]; then
USE_TABLES=$(get_cache_var "USE_TABLES")
[ -n "$USE_TABLES" ] && { ${APP_PATH}/${USE_TABLES}.sh update_wan_sets >/dev/null 2>&1 & }
exit 0
fi
[ ! -d ${LOCK_PATH} ] && mkdir -p ${LOCK_PATH}
LOCK_FILE="${LOCK_PATH}/${CONFIG}_ifup.lock"
if [ -s ${LOCK_FILE} ]; then
SPID=$(cat ${LOCK_FILE})
if [ -e /proc/${SPID}/status ]; then
exit 1
fi
cat /dev/null > ${LOCK_FILE}
fi
echo $$ > ${LOCK_FILE}
/etc/init.d/${CONFIG} restart >/dev/null 2>&1 &
logger -p notice -t network -s "${CONFIG}: restart when $INTERFACE ifup"
rm -rf ${LOCK_FILE}
}
mkdir -p "$LOCK_PATH" || {
logger -p err -t network -s "${CONFIG}: cannot create lock directory $LOCK_PATH"
exit 1
}
(
command exec 9>"${LOCK_PATH}/${CONFIG}_ifup.lock" || {
logger -p err -t network -s "${CONFIG}: cannot open ifup lock"
exit 1
}
flock -xn 9 || exit 0
# Keep this lock file: removing it would allow locks on different inodes.
# The worker holds the lock until restart returns; children must not inherit it.
logger -p notice -t network -s "${CONFIG}: restart when $INTERFACE ifup" 9>&-
"/etc/init.d/${CONFIG}" restart 9>&-
) </dev/null >/dev/null 2>&1 &
exit 0
+30 -26
View File
@@ -9,31 +9,30 @@ APP_FILE=${APP_PATH}/app.sh
LOCK_FILE=${LOCK_PATH}/${CONFIG}.lock
set_lock() {
[ ! -d "$LOCK_PATH" ] && mkdir -p $LOCK_PATH
exec 999>"$LOCK_FILE"
flock -xn 999
mkdir -p "$LOCK_PATH" || return 1
command exec 9>"$LOCK_FILE" || return 1
flock -xn 9
}
set_lock_wait() {
[ ! -d "$LOCK_PATH" ] && mkdir -p "$LOCK_PATH"
exec 999>"$LOCK_FILE"
flock -x 999
mkdir -p "$LOCK_PATH" || return 1
command exec 9>"$LOCK_FILE" || return 1
flock -x 9
}
unset_lock() {
flock -u 999
flock -u 9
exec 9>&-
}
boot_func() {
rm -f ${LOCK_PATH}/${CONFIG}_ready.lock
rm -f ${LOCK_PATH}/${CONFIG}_rule_update.lock
rm -f ${LOCK_PATH}/${CONFIG}_subscribe.lock
local delay=$(uci -q get ${CONFIG}.@global_delay[0].start_delay || echo 1)
if [ "$delay" -gt 0 ]; then
echolog "执行启动延时 $delay 秒后再启动!"
sleep $delay
fi
restart boot
restart boot || return 1
touch ${LOCK_PATH}/${CONFIG}_ready.lock
}
@@ -42,35 +41,40 @@ boot() {
}
start() {
set_lock
[ $? == 1 ] && echolog "脚本已经在运行,不重复运行,退出." && exit 0
$APP_FILE start $2
set_lock || { echolog "脚本已经在运行,不重复运行,退出."; return 0; }
"$APP_FILE" start "$2" 9>&-
unset_lock
}
stop() {
set_lock_wait
[ $? != 0 ] && echolog "无法取得停止锁,退出." && exit 1
$APP_FILE stop $2
set_lock_wait || { echolog "无法取得停止锁,退出."; return 1; }
"$APP_FILE" stop "$2" 9>&-
unset_lock
}
restart() {
local action=${2:-$1}
[ "$action" = "restart" ] && action=
set_lock
[ $? == 1 ] && echolog "脚本已经在运行,不重复运行,退出." && exit 0
rule_lock=${LOCK_PATH}/${CONFIG}_rule_update.lock
sub_lock=${LOCK_PATH}/${CONFIG}_subscribe.lock
set_lock || { echolog "脚本已经在运行,不重复运行,退出."; return 0; }
local update_status=1
for i in $(seq 1 300); do
if [ ! -f "$rule_lock" ] && [ ! -f "$sub_lock" ]; then
break
fi
PASSWALL_UPDATE_LOCK="${LOCK_PATH}/${CONFIG}_sub_rule.lock" lua -e '
local nixio = require "nixio"
local file = nixio.open(os.getenv("PASSWALL_UPDATE_LOCK"), "a")
if not file then os.exit(2) end
os.exit(file:lock("tlock") and 0 or 1)
'
update_status=$?
[ "$update_status" -ne 1 ] && break
sleep 2
done
rm -f "$rule_lock" "$sub_lock"
$APP_FILE stop $action
$APP_FILE start $action
if [ "$update_status" -ne 0 ]; then
echolog "等待订阅/规则更新结束失败或超时,取消重启."
unset_lock
return 1
fi
"$APP_FILE" stop "$action" 9>&-
"$APP_FILE" start "$action" 9>&-
unset_lock
}
@@ -1805,12 +1805,6 @@ stop() {
rm -f ${LOCK_PATH}/${CONFIG}_socks_auto_switch*
rm -f ${LOCK_PATH}/${CONFIG}_lease2hosts*
rm -f ${LOCK_PATH}/${CONFIG}_monitor*
if ! busybox pgrep -af "${CONFIG}/" | grep -q '/subscribe\.lua'; then
rm -f "${LOCK_PATH}/${CONFIG}_subscribe.lock"
fi
if ! busybox pgrep -af "${CONFIG}/" | grep -q '/rule_update\.lua'; then
rm -f "${LOCK_PATH}/${CONFIG}_rule_update.lock"
fi
echolog "清空并关闭相关程序和缓存完成。"
exit 0
}
@@ -7,6 +7,34 @@ local jsonc = api.jsonc
local fs = api.fs
local uci, uci_get, uci_set, uci_del, uci_foreach, uci_save = api.uci, api.uci_get_c, api.uci_set_c, api.uci_del_c, api.uci_foreach_c, api.uci_save_c
-- [[ 逻辑锁 Start ]] --
-- Both update scripts use the same lockf lock; the kernel releases it on exit.
local update_lock = api.nixio.open(api.LOCK_PREFIX .. "_sub_rule.lock", api.nixio.open_flags("rdwr", "creat"))
if not update_lock then
api.log("无法打开订阅/规则更新锁,退出。")
os.exit(1)
end
-- Scheduled updates wait for the lock; manual requests may skip a busy lock.
if not update_lock:lock("tlock") then
if arg[3] ~= "cron" then
api.log("订阅或规则更新正在运行,本次请求跳过。")
os.exit(0)
end
local running = ({s = "订阅", r = "规则更新"})[update_lock:read(1)] or "订阅/规则更新"
update_lock:seek(0)
api.log("[" .. running .. "]实例正在运行,[规则更新]进入队列等待...")
if not update_lock:lock("lock") then
api.log("无法取得更新锁,计划任务失败。")
os.exit(1)
end
end
-- Record the running task in the same file: s = subscription, r = rule update.
update_lock:write("r")
update_lock:seek(0)
api.uci:revert(api.c_config)
math.randomseed(os.time() + math.floor(os.clock() * 1000))
-- [[ 逻辑锁 End ]] --
local arg1 = arg[1]
local arg2 = arg[2]
local arg3 = arg[3]
@@ -668,37 +696,10 @@ else
geosite_update = uci_get("@global_rules[0]", "geosite_update") or "1"
end
if geo2rule ~= "1" and gfwlist_update == "0" and chnroute_update == "0" and chnroute6_update == "0" and chnlist_update == "0" and geoip_update == "0" and geosite_update == "0" then
os.exit(0)
update_lock:close()
return
end
local function check_instance(action)
local rule_lock = api.LOCK_PREFIX .. "_rule_update.lock"
local sub_lock = api.LOCK_PREFIX .. "_subscribe.lock"
if action == "start" then
math.randomseed(os.time() + math.floor(os.clock() * 1000))
api.nixio.nanosleep(0, math.random(100, 1000) * 1000000)
if fs.access(rule_lock) then
log("有[规则更新]实例正在运行,请稍后再试...\n")
os.exit(0)
else
luci.sys.call("touch " .. rule_lock)
end
elseif action == "end" then
api.remove(rule_lock)
return
end
if fs.access(sub_lock) then
log("[订阅]实例正在运行,[规则更新]进入队列等待...\n")
end
while fs.access(sub_lock) do
api.nixio.nanosleep(2, 0)
end
end
check_instance("start")
log("开始更新规则...")
local function safe_call(func, err_msg)
xpcall(func, function(e)
@@ -803,9 +804,11 @@ if reboot == 1 then
log("重启服务,应用新的规则。")
uci_set("@global[0]", "flush_set", "1")
uci_save(true)
local action = (arg3 == "cron") and " cron" or ""
luci.sys.call("/etc/init.d/passwall restart%s > /dev/null 2>&1 &" % action)
end
log("规则更新完毕...\n")
check_instance("end")
update_lock:close()
if reboot == 1 then
local action = arg3 == "cron" and " cron" or ""
luci.sys.call("/etc/init.d/passwall restart" .. action .. " > /dev/null 2>&1 &")
end
@@ -24,6 +24,36 @@ local uci, uci_get, uci_set, uci_del, uci_foreach, uci_save = api.uci, api.uci_g
local tinsert = table.insert
local ssub, slen, schar, sbyte, sformat, sgsub = string.sub, string.len, string.char, string.byte, string.format, string.gsub
-- [[ 逻辑锁 Start ]] --
if not arg[1] then os.exit(0) end
-- Both update scripts use the same lockf lock; the kernel releases it on exit.
local update_lock = api.nixio.open(api.LOCK_PREFIX .. "_sub_rule.lock", api.nixio.open_flags("rdwr", "creat"))
if not update_lock then
api.log("无法打开订阅/规则更新锁,退出。")
os.exit(1)
end
-- Scheduled updates wait for the lock; manual requests may skip a busy lock.
if not update_lock:lock("tlock") then
if arg[3] ~= "cron" then
api.log("订阅或规则更新正在运行,本次请求跳过。")
os.exit(0)
end
local running = ({s = "订阅", r = "规则更新"})[update_lock:read(1)] or "订阅/规则更新"
update_lock:seek(0)
api.log("[" .. running .. "]实例正在运行,[订阅]进入队列等待...")
if not update_lock:lock("lock") then
api.log("无法取得更新锁,计划任务失败。")
os.exit(1)
end
end
-- Record the running task in the same file: s = subscription, r = rule update.
update_lock:write("s")
update_lock:seek(0)
api.uci:revert(c_config)
math.randomseed(os.time() + math.floor(os.clock() * 1000))
local restart_required = false
-- [[ 逻辑锁 End ]] --
local has_ss_rust = api.is_finded("sslocal")
local has_ssr = api.is_finded("ssr-local") and api.is_finded("ssr-redir")
local has_singbox = api.finded_com("sing-box")
@@ -2107,10 +2137,7 @@ local function update_node(manual)
uci_save(true)
local action = (arg[3] == "cron") and " cron" or ""
if manual ~= 1 then
luci.sys.call("/etc/init.d/passwall restart%s > /dev/null 2>&1 &" % action)
end
if manual ~= 1 then restart_required = true end
end
local function parse_link(raw, add_mode, group, sub_cfg)
@@ -2282,56 +2309,28 @@ local execute = function()
end
end
local function check_instance(action)
local sub_lock = api.LOCK_PREFIX .. "_subscribe.lock"
local rule_lock = api.LOCK_PREFIX .. "_rule_update.lock"
if action == "start" then
math.randomseed(os.time() + math.floor(os.clock() * 1000))
api.nixio.nanosleep(0, math.random(100, 1000) * 1000000)
if fs.access(sub_lock) then
log("有[订阅]实例正在运行,请稍后再试...\n")
os.exit(0)
else
luci.sys.call("touch " .. sub_lock)
uci:revert(c_config)
if arg[1] == "start" then
log('开始订阅...')
xpcall(execute, function(e)
log(e)
if type(debug) == "table" and type(debug.traceback) == "function" then
log(debug.traceback())
end
elseif action == "end" then
api.remove(sub_lock)
return
end
if fs.access(rule_lock) then
log("[规则更新]实例正在运行,[订阅]进入队列等待...\n")
end
while fs.access(rule_lock) do
api.nixio.nanosleep(2, 0)
end
log('订阅发生错误。')
end)
log('订阅完毕...\n')
elseif arg[1] == "add" then
local f = assert(io.open("/tmp/links.conf", 'r'))
local raw = f:read('*all')
f:close()
parse_link(raw, "1", arg[2])
update_node(1)
api.remove("/tmp/links.conf")
elseif arg[1] == "truncate" then
truncate_nodes(arg[2])
end
if arg[1] then
check_instance("start")
if arg[1] == "start" then
log('开始订阅...')
xpcall(execute, function(e)
log(e)
if type(debug) == "table" and type(debug.traceback) == "function" then
log(debug.traceback())
end
log('发生错误, 正在恢复服务')
end)
log('订阅完毕...\n')
elseif arg[1] == "add" then
local f = assert(io.open("/tmp/links.conf", 'r'))
local raw = f:read('*all')
f:close()
parse_link(raw, "1", arg[2])
update_node(1)
api.remove("/tmp/links.conf")
elseif arg[1] == "truncate" then
truncate_nodes(arg[2])
end
check_instance("end")
update_lock:close()
if restart_required then
local action = arg[3] == "cron" and " cron" or ""
luci.sys.call("/etc/init.d/passwall restart" .. action .. " > /dev/null 2>&1 &")
end