update 2026-10-25 16:53:21

This commit is contained in:
action committed 2026-10-25 16:53:21 +08:00
1 parent 91f217be10
commit 7fca8e9a3a
74 files changed
+1429 -918

No files matched your search

@@ -2,6 +2,28 @@
PATH="/usr/sbin:/usr/bin:/sbin:/bin"
update_mode=$1
# Keep the lock file: unlinking it would allow a second lock on a new inode.
exec 9>/var/lock/AdGuardHome-update.lock || exit 1
# Allow a brief status probe to finish before treating the lock as busy.
if ! flock -w 1 9; then
printf '%s\n' '已经有更新任务正在运行,请等待其结束。'
exit 2
fi
# Only the lock owner may reset the log and update status.
exec >/tmp/AdGuardHome_update.log 2>&1
cleanup() {
local result=$?
trap - EXIT
[ "$result" -ne 0 ] && touch /var/run/update_core_error
rm -f /var/run/update_core
exit "$result"
}
trap cleanup EXIT
trap 'exit 1' TERM INT HUP
rm -f /var/run/update_core_error
touch /var/run/update_core
binpath=$(uci get AdGuardHome.AdGuardHome.binpath 2>/dev/null)
if [ -z "$binpath" ]; then
uci set AdGuardHome.AdGuardHome.binpath="/tmp/AdGuardHome/AdGuardHome"
@@ -11,31 +33,9 @@ fi
enabled=$(uci get AdGuardHome.AdGuardHome.enabled 2>/dev/null)
core_api_url="https://api.github.com/repos/AdguardTeam/AdGuardHome/releases/latest"
Check_Task(){
running_tasks=$(pgrep -f "update_core.sh" 2>/dev/null | grep -v "^$$\$" | wc -l)
running_tasks=${running_tasks:-0}
case $1 in
force)
printf "%s\n" "执行: 强制更新核心"
if [ "$running_tasks" -gt 0 ]; then
printf "%s\n" "清除 ${running_tasks} 个进程 ..."
pkill -9 -f "update_core.sh" 2>/dev/null
sleep 1
fi
;;
*)
if [ "$running_tasks" -gt 1 ]; then
printf "%s\n" "已经有更新任务正在运行, 请等待其执行结束或点击强制更新!"
EXIT 2
fi
;;
esac
}
Check_Updates(){
downloader_cmd="uclient-fetch"
downloader_opts="--no-check-certificate -T 5 -q -O"
downloader_opts="-T 5 -q -O"
downloader_quiet_opts="-q -O -"
printf "%s\n" "开始检查更新, 请耐心等待 ..."
Cloud_Version="$(${downloader_cmd} ${downloader_quiet_opts} "$core_api_url" 2>/dev/null | sed -n 's/.*"tag_name":[ ]*"\(v[^"]*\)".*/\1/p' | head -n 1)"
@@ -67,7 +67,7 @@ Update_Core(){
printf "\n开始下载 AdGuardHome 核心文件 ...\n\n"
${downloader_cmd} ${downloader_opts} "/tmp/AdGuardHome_Update/${link##*/}" "$link" > /dev/null 2>&1
if [ $? -ne 0 ]; then
printf "\nAdGuardHome 核心下载失败 ...\n"
printf "\nAdGuardHome 核心下载失败,请检查网络、系统时间及 CA 证书 ...\n"
rm -rf /tmp/AdGuardHome_Update
EXIT 1
fi
@@ -87,10 +87,9 @@ Update_Core(){
chmod +x "$downloadbin"
size_bytes=$(wc -c < "$downloadbin" 2>/dev/null || echo 0)
printf "\nAdGuardHome 核心体积: %s\n" "$(awk -v bytes="$size_bytes" 'BEGIN{printf "%.2fMB", bytes/1000000}')"
/etc/init.d/AdGuardHome stop > /dev/null 2>&1
/etc/init.d/AdGuardHome stop 9>&- > /dev/null 2>&1
printf "\n移动 AdGuardHome 核心文件到 %s ...\n" "${binpath%/*}"
mv -f "$downloadbin" "$binpath" > /dev/null 2>&1
if [ ! -s "$binpath" ] && [ $? -ne 0 ]; then
if ! mv -f "$downloadbin" "$binpath" > /dev/null 2>&1 || [ ! -s "$binpath" ]; then
printf "AdGuardHome 核心移动失败!\n可能是设备空间不足导致, 请尝试更改 [执行文件路径] 为 /tmp/AdGuardHome\n"
EXIT 1
fi
@@ -98,7 +97,7 @@ Update_Core(){
chmod +x "$binpath"
if [ "$enabled" = 1 ]; then
printf "\n正在重启 AdGuardHome 服务...\n"
/etc/init.d/AdGuardHome restart > /dev/null 2>&1
/etc/init.d/AdGuardHome restart 9>&- > /dev/null 2>&1
fi
printf "\nAdGuardHome 核心更新成功!\n"
}
@@ -159,18 +158,7 @@ GET_Arch() {
}
EXIT(){
rm -rf /var/run/update_core $LOCKU 2>/dev/null
[ "$1" -ne 0 ] && touch /var/run/update_core_error
exit $1
exit "$1"
}
main(){
Check_Task "$update_mode"
Check_Updates "$update_mode"
}
trap "EXIT 1" SIGTERM SIGINT
touch /var/run/update_core
rm -rf /var/run/update_core_error 2>/dev/null
main
Check_Updates "$update_mode"
@@ -1,6 +1,6 @@
{
"admin/services/AdGuardHomeJS": {
"title": "AdGuard Home JS",
"admin/services/AdGuardHome": {
"title": "AdGuard Home",
"order": 12,
"action": {
"type": "firstchild"
@@ -9,7 +9,7 @@
"acl": [ "luci-app-adguardhome" ]
}
},
"admin/services/AdGuardHomeJS/base": {
"admin/services/AdGuardHome/base": {
"title": "Base Setting",
"order": 1,
"action": {
@@ -20,7 +20,7 @@
"acl": [ "luci-app-adguardhome" ]
}
},
"admin/services/AdGuardHomeJS/log": {
"admin/services/AdGuardHome/log": {
"title": "Log",
"order": 3,
"action": {
@@ -31,7 +31,7 @@
"acl": [ "luci-app-adguardhome" ]
}
},
"admin/services/AdGuardHomeJS/manual": {
"admin/services/AdGuardHome/manual": {
"title": "Manual Config",
"order": 2,
"action": {
@@ -42,4 +42,4 @@
"acl": [ "luci-app-adguardhome" ]
}
}
}
}
@@ -7,13 +7,13 @@
},
"ubus": {
"service": [ "list" ],
"luci.adguardhome": [ "getCoreInfo", "getCoreUpdate", "getInterfaces", "getRuntimeLog", "getManualConfig" ]
"luci.adguardhome": [ "getCoreInfo", "getRedirectStatus", "getCoreUpdate", "getInterfaces", "getRuntimeLog", "getManualConfig" ]
},
"uci": [ "AdGuardHome" ]
},
"write": {
"ubus": {
"luci.adguardhome": [ "startCoreUpdate", "changeWebPassword", "clearRuntimeLog", "setManualConfig" ]
"luci.adguardhome": [ "setVerboseLog", "startCoreUpdate", "changeWebPassword", "clearRuntimeLog", "setManualConfig" ]
},
"uci": [ "AdGuardHome" ]
}
@@ -1,15 +1,48 @@
#!/usr/bin/ucode
'use strict';
import { stat, popen, readfile, writefile, unlink, lsdir } from 'fs';
import { stat, open, popen, readfile, writefile, unlink, lsdir } from 'fs';
import { cursor } from 'uci';
function shellQuote(value) {
return "'" + replace(value, /'/g, "'\\''") + "'";
}
function coreUpdateRunning() {
// The kernel releases the lock even if the updater is killed.
const result = system(['/usr/bin/flock', '-n', '-E', '2',
'/var/lock/AdGuardHome-update.lock', '/bin/true'], 3000);
if (result != 0 && result != 2)
die('Unable to check core update lock');
return result == 2;
}
return {
'luci.adguardhome': {
getRedirectStatus: {
call: function() {
const conf = cursor();
function option(name, fallback) {
const value = conf.get('AdGuardHome', 'AdGuardHome', name);
return (type(value) == 'array' ? value[0] : value) || fallback;
}
const result = {
mode: option('redirect', 'none'),
enabled: option('enabled', '0') == '1',
applied_mode: option('old_redirect', 'none'),
applied_enabled: option('old_enabled', '0') == '1',
binpath: option('binpath', '/usr/bin/AdGuardHome/AdGuardHome'),
redirected: trim(readfile('/var/run/AdGredir') || '') == '1'
};
conf.unload('AdGuardHome');
const lock = system(['/usr/bin/flock', '-n', '-E', '2',
'/var/lock/AdGuardHome-redirect.lock', '/bin/true'], 3000);
if (lock != 0 && lock != 2)
die('Unable to check redirect status');
result.busy = lock == 2;
return result;
}
},
getManualConfig: {
call: function() {
const conf = cursor();
@@ -98,8 +131,9 @@ return {
},
getCoreUpdate: {
call: function() {
const running = stat('/var/run/update_core') != null;
const failed = stat('/var/run/update_core_error') != null;
const running = coreUpdateRunning();
const failed = stat('/var/run/update_core_error') != null ||
(!running && stat('/var/run/update_core') != null);
const log = readfile('/tmp/AdGuardHome_update.log', 131072) || '';
return {
@@ -111,15 +145,12 @@ return {
startCoreUpdate: {
args: { force: false },
call: function(request) {
if (stat('/var/run/update_core') != null)
if (coreUpdateRunning())
return { started: false, reason: 'busy' };
unlink('/var/run/update_core_error');
unlink('/tmp/AdGuardHome_update.log');
const command = request.args.force
? '/bin/sh /usr/share/AdGuardHome/update_core.sh force >/tmp/AdGuardHome_update.log 2>&1 </dev/null &'
: '/bin/sh /usr/share/AdGuardHome/update_core.sh >/tmp/AdGuardHome_update.log 2>&1 </dev/null &';
? '/bin/sh /usr/share/AdGuardHome/update_core.sh force >/dev/null 2>&1 </dev/null &'
: '/bin/sh /usr/share/AdGuardHome/update_core.sh >/dev/null 2>&1 </dev/null &';
return { started: system(['/bin/sh', '-c', command], 3000) == 0 };
}
@@ -150,8 +181,22 @@ return {
return { changed: true };
}
},
setVerboseLog: {
args: { enabled: false },
call: function(request) {
const conf = cursor();
if (!conf.set('AdGuardHome', 'AdGuardHome', 'verbose', request.args.enabled ? '1' : '0') ||
!conf.commit('AdGuardHome'))
return { saved: false, applied: false };
conf.unload('AdGuardHome');
return {
saved: true,
applied: system(['/etc/init.d/AdGuardHome', 'reload'], 30000) == 0
};
}
},
getRuntimeLog: {
args: { offset: 0 },
args: { offset: 0, identity: '' },
call: function(request) {
const conf = cursor();
const logfile = conf.get('AdGuardHome', 'AdGuardHome', 'logfile') || '';
@@ -167,18 +212,40 @@ return {
system(['/bin/sh', '-c', '/bin/sh /usr/share/AdGuardHome/getsyslog.sh >/dev/null 2>&1 &'], 3000);
}
const log = readfile(source) || '';
const size = length(log);
let offset = +request.args.offset || 0;
if (offset < 0 || offset > size)
// Bound memory and start with the most recent 256 KiB on a new view.
const limit = 262144;
const info = stat(source);
const identity = info ? source + ':' + info.dev.major + ':' + info.dev.minor + ':' + info.inode : '';
let offset = int(request.args.offset) || 0;
let reset = request.args.identity != identity || offset < 0 || offset > (info?.size || 0);
if (reset)
offset = 0;
const content = substr(log, offset, 2097152);
if (info && info.size - offset > limit) {
offset = info.size - limit;
reset = true;
}
let content = '';
if (info?.type == 'file') {
const file = open(source, 'r');
if (!file)
die('Unable to open runtime log');
const positioned = file.seek(offset);
const chunk = positioned ? file.read(limit) : null;
file.close();
if (chunk == null)
die('Unable to read runtime log');
content = chunk;
}
return {
enabled: true,
localtime: logfile != 'syslog',
content: content,
offset: offset + length(content)
// ubus strings stop at NUL; cleared files can contain sparse zero-filled gaps.
content_b64: b64enc(content),
offset: offset + length(content),
identity: identity,
reset: reset
};
}
},