fix(apk): sanitize orphaned sing-box packages in apk world and add force-overwrite
This commit is contained in:
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-17 07:46+0300\n"
|
"POT-Creation-Date: 2026-09-17 08:16+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-17 07:46+0300\n"
|
"PO-Revision-Date: 2026-09-17 08:16+0300\n"
|
||||||
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-17 10:46+0300\n"
|
"POT-Creation-Date: 2026-09-17 11:16+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-17 10:46+0300\n"
|
"PO-Revision-Date: 2026-09-17 11:16+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
|
|||||||
+39
-2
@@ -423,12 +423,29 @@ run_logged_timeout() {
|
|||||||
return "$_rc"
|
return "$_rc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Clean up orphaned sing-box package references in /etc/apk/world that prevent apk from resolving dependencies
|
||||||
|
sanitize_apk_world() {
|
||||||
|
[ "$PKG_IS_APK" -eq 1 ] || return 0
|
||||||
|
[ -f /etc/apk/world ] || return 0
|
||||||
|
|
||||||
|
local _orphaned_pkg
|
||||||
|
for _orphaned_pkg in sing-box-extended sing-box sing-box-tiny sing-box-lx; do
|
||||||
|
if grep -E -q "^${_orphaned_pkg}([><= ].*)?$" /etc/apk/world 2>/dev/null; then
|
||||||
|
if ! apk info -e "$_orphaned_pkg" >/dev/null 2>&1; then
|
||||||
|
log_line "WARN removing orphaned $_orphaned_pkg from /etc/apk/world"
|
||||||
|
sed -i -E "/^${_orphaned_pkg}([><= ].*)?$/d" /etc/apk/world 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# Retry an APK command up to 10 times if the database is locked (exit 227).
|
# Retry an APK command up to 10 times if the database is locked (exit 227).
|
||||||
# Usage: apk_with_lock_retry <tag> <timeout> <apk args...>
|
# Usage: apk_with_lock_retry <tag> <timeout> <apk args...>
|
||||||
apk_with_lock_retry() {
|
apk_with_lock_retry() {
|
||||||
local _tag="$1" _secs="$2"
|
local _tag="$1" _secs="$2"
|
||||||
shift 2
|
shift 2
|
||||||
local _attempt=0 _rc=227
|
local _attempt=0 _rc=227
|
||||||
|
sanitize_apk_world
|
||||||
while [ "$_attempt" -lt 10 ] && [ "$_rc" -eq 227 ]; do
|
while [ "$_attempt" -lt 10 ] && [ "$_rc" -eq 227 ]; do
|
||||||
if [ "$_attempt" -gt 0 ]; then
|
if [ "$_attempt" -gt 0 ]; then
|
||||||
log_line "WARN [$_tag] APK database locked (exit 227), retrying in 3s (attempt $((_attempt+1))/10)..."
|
log_line "WARN [$_tag] APK database locked (exit 227), retrying in 3s (attempt $((_attempt+1))/10)..."
|
||||||
@@ -462,6 +479,11 @@ warn() {
|
|||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
log_line "FAIL $1"
|
log_line "FAIL $1"
|
||||||
|
if [ "${TACHYON_WAS_RUNNING:-0}" -eq 1 ] && [ -x /etc/init.d/tachyon ]; then
|
||||||
|
log_line "WARN restoring Tachyon service after failed install"
|
||||||
|
/etc/init.d/tachyon enable 2>/dev/null || true
|
||||||
|
/etc/init.d/tachyon restart 2>/dev/null || true
|
||||||
|
fi
|
||||||
if command -v tui_err >/dev/null 2>&1; then
|
if command -v tui_err >/dev/null 2>&1; then
|
||||||
tui_err "$1"
|
tui_err "$1"
|
||||||
else
|
else
|
||||||
@@ -1138,11 +1160,18 @@ function installer_package_installed(name) {
|
|||||||
|
|
||||||
function installer_remove_package(name) {
|
function installer_remove_package(name) {
|
||||||
name = as_string(name);
|
name = as_string(name);
|
||||||
if (name == "" || !installer_package_installed(name))
|
if (name == "")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (installer_package_manager() == "apk")
|
if (installer_package_manager() == "apk") {
|
||||||
|
if (file_exists("/etc/apk/world"))
|
||||||
|
command_success("sed -i -E " + shell_quote("/^" + name + "([><= ].*)?$/d") + " /etc/apk/world 2>/dev/null");
|
||||||
|
if (!installer_package_installed(name))
|
||||||
|
return true;
|
||||||
return run_args([ "timeout", "120", "apk", "del", name ]);
|
return run_args([ "timeout", "120", "apk", "del", name ]);
|
||||||
|
}
|
||||||
|
if (!installer_package_installed(name))
|
||||||
|
return true;
|
||||||
return run_args([ "timeout", "120", "opkg", "remove", "--force-depends", name ]);
|
return run_args([ "timeout", "120", "opkg", "remove", "--force-depends", name ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1442,6 +1471,13 @@ function installer_cleanup_legacy() {
|
|||||||
remove_path("/etc/netshift");
|
remove_path("/etc/netshift");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (installer_package_manager() == "apk" && file_exists("/etc/apk/world")) {
|
||||||
|
for (let orphaned_pkg in [ "sing-box-extended", "sing-box", "sing-box-tiny", "sing-box-lx" ]) {
|
||||||
|
if (!installer_package_installed(orphaned_pkg))
|
||||||
|
command_success("sed -i -E " + shell_quote("/^" + orphaned_pkg + "([><= ].*)?$/d") + " /etc/apk/world 2>/dev/null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!installer_remove_package_prefix("luci-i18n-tachyon"))
|
if (!installer_remove_package_prefix("luci-i18n-tachyon"))
|
||||||
packages_removed = false;
|
packages_removed = false;
|
||||||
if (!installer_remove_package("luci-app-tachyon"))
|
if (!installer_remove_package("luci-app-tachyon"))
|
||||||
@@ -2826,6 +2862,7 @@ download_tachyon_packages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_backend_package() {
|
install_backend_package() {
|
||||||
|
sanitize_apk_world
|
||||||
msg "$(installer_text kmod_check)"
|
msg "$(installer_text kmod_check)"
|
||||||
for kmod in kmod-inet-diag kmod-netlink-diag kmod-tun kmod-nft-tproxy kmod-nft-nat; do
|
for kmod in kmod-inet-diag kmod-netlink-diag kmod-tun kmod-nft-tproxy kmod-nft-nat; do
|
||||||
if ! pkg_is_installed "$kmod"; then
|
if ! pkg_is_installed "$kmod"; then
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-17 10:46+0300\n"
|
"POT-Creation-Date: 2026-09-17 11:16+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-17 10:46+0300\n"
|
"PO-Revision-Date: 2026-09-17 11:16+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-17 07:46+0300\n"
|
"POT-Creation-Date: 2026-09-17 08:16+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-17 07:46+0300\n"
|
"PO-Revision-Date: 2026-09-17 08:16+0300\n"
|
||||||
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ function pkg_install_files_command(files, force_reinstall) {
|
|||||||
let add_args = [ "apk", "add", "--allow-untrusted" ];
|
let add_args = [ "apk", "add", "--allow-untrusted" ];
|
||||||
for (let file in files)
|
for (let file in files)
|
||||||
push(add_args, file);
|
push(add_args, file);
|
||||||
let extract_args = [ "apk", "extract", "--allow-untrusted", "--destination", "/" ];
|
let extract_args = [ "apk", "extract", "--allow-untrusted", "--force-overwrite", "--destination", "/" ];
|
||||||
for (let file in files)
|
for (let file in files)
|
||||||
push(extract_args, file);
|
push(extract_args, file);
|
||||||
return "(" + command_from_args(add_args) + " </dev/null || " + command_from_args(extract_args) + " </dev/null)";
|
return "(" + command_from_args(add_args) + " </dev/null || " + command_from_args(extract_args) + " </dev/null)";
|
||||||
@@ -476,13 +476,24 @@ function pkg_install_files_command(files, force_reinstall) {
|
|||||||
return "(" + opkg_cmd + " || (" + join(" && ", fallback_cmds) + "))";
|
return "(" + opkg_cmd + " || (" + join(" && ", fallback_cmds) + "))";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sanitize_apk_world() {
|
||||||
|
if (!is_apk() || !file_exists("/etc/apk/world"))
|
||||||
|
return;
|
||||||
|
for (let pkg in [ "sing-box-extended", "sing-box", "sing-box-tiny", "sing-box-lx" ]) {
|
||||||
|
if (!pkg_is_installed(pkg))
|
||||||
|
command_success("sed -i -E " + shell_quote("/^" + pkg + "([><= ].*)?$/d") + " /etc/apk/world 2>/dev/null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function pkg_install_files(files, force_reinstall) {
|
function pkg_install_files(files, force_reinstall) {
|
||||||
|
sanitize_apk_world();
|
||||||
return command_success(pkg_install_files_command(files, force_reinstall));
|
return command_success(pkg_install_files_command(files, force_reinstall));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like run_logged but retries up to 10 times on package manager database lock (exit code 227 for APK, lock file contention for opkg)
|
// Like run_logged but retries up to 10 times on package manager database lock (exit code 227 for APK, lock file contention for opkg)
|
||||||
function run_logged_retrying(description, command) {
|
function run_logged_retrying(description, command) {
|
||||||
init_tmp_dir();
|
init_tmp_dir();
|
||||||
|
sanitize_apk_world();
|
||||||
let output_file = make_tmp_file("command");
|
let output_file = make_tmp_file("command");
|
||||||
if (output_file == "")
|
if (output_file == "")
|
||||||
output_file = "/tmp/tachyon-updates-command." + owner_pid();
|
output_file = "/tmp/tachyon-updates-command." + owner_pid();
|
||||||
@@ -498,7 +509,8 @@ function run_logged_retrying(description, command) {
|
|||||||
}
|
}
|
||||||
status = command_status(as_string(command) + " >" + shell_quote(output_file) + " 2>&1");
|
status = command_status(as_string(command) + " >" + shell_quote(output_file) + " 2>&1");
|
||||||
let output_text = read_file(output_file);
|
let output_text = read_file(output_file);
|
||||||
let is_locked = status == 227 || (status == 255 && match(output_text, /Could not lock|opkg\.lock|Resource temporarily unavailable/i) != null);
|
let is_locked = (status == 227 || (status == 255 && match(output_text, /Could not lock|opkg\.lock|Resource temporarily unavailable/i) != null)) &&
|
||||||
|
match(output_text, /unable to select packages|no such package/i) == null;
|
||||||
if (!is_locked)
|
if (!is_locked)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -517,14 +529,22 @@ function run_logged_retrying(description, command) {
|
|||||||
|
|
||||||
function pkg_remove_sing_box_conflict(package_name) {
|
function pkg_remove_sing_box_conflict(package_name) {
|
||||||
package_name = as_string(package_name);
|
package_name = as_string(package_name);
|
||||||
|
if (is_apk()) {
|
||||||
|
if (file_exists("/etc/apk/world"))
|
||||||
|
command_success("sed -i -E " + shell_quote("/^" + package_name + "([><= ].*)?$/d") + " /etc/apk/world 2>/dev/null");
|
||||||
|
if (!pkg_is_installed(package_name))
|
||||||
|
return true;
|
||||||
|
return command_success(command_from_args([ "apk", "del", "--force-broken-world", package_name ]) + " </dev/null");
|
||||||
|
}
|
||||||
if (!pkg_is_installed(package_name))
|
if (!pkg_is_installed(package_name))
|
||||||
return true;
|
return true;
|
||||||
if (is_apk())
|
|
||||||
return command_success(command_from_args([ "apk", "del", "--force-broken-world", package_name ]) + " </dev/null");
|
|
||||||
return command_success(command_from_args([ "opkg", "remove", "--force-depends", package_name ]) + " </dev/null");
|
return command_success(command_from_args([ "opkg", "remove", "--force-depends", package_name ]) + " </dev/null");
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_logged_pkg_remove_sing_box_conflict(package_name, description) {
|
function run_logged_pkg_remove_sing_box_conflict(package_name, description) {
|
||||||
|
if (is_apk() && file_exists("/etc/apk/world"))
|
||||||
|
command_success("sed -i -E " + shell_quote("/^" + package_name + "([><= ].*)?$/d") + " /etc/apk/world 2>/dev/null");
|
||||||
|
|
||||||
if (!pkg_is_installed(package_name)) {
|
if (!pkg_is_installed(package_name)) {
|
||||||
updates_log(description);
|
updates_log(description);
|
||||||
return true;
|
return true;
|
||||||
@@ -2189,6 +2209,8 @@ function write_sing_box_variant_state(marker, version) {
|
|||||||
updates_log("Failed to write sing-box variant marker", "warn");
|
updates_log("Failed to write sing-box variant marker", "warn");
|
||||||
if (!sing_box_runtime_success("write-version-state", [ version ]))
|
if (!sing_box_runtime_success("write-version-state", [ version ]))
|
||||||
updates_log("Failed to write sing-box version state", "warn");
|
updates_log("Failed to write sing-box version state", "warn");
|
||||||
|
if (marker != "extended")
|
||||||
|
sanitize_apk_world();
|
||||||
}
|
}
|
||||||
|
|
||||||
function restore_sing_box_variant_state(previous_marker, previous_version_state) {
|
function restore_sing_box_variant_state(previous_marker, previous_version_state) {
|
||||||
|
|||||||
@@ -331,10 +331,32 @@ fi
|
|||||||
|
|
||||||
if command -v apk >/dev/null 2>&1 && [ -d "/lib/apk/db" ]; then
|
if command -v apk >/dev/null 2>&1 && [ -d "/lib/apk/db" ]; then
|
||||||
for _pkg in luci-i18n-tachyon-ru luci-app-tachyon tachyon; do
|
for _pkg in luci-i18n-tachyon-ru luci-app-tachyon tachyon; do
|
||||||
|
if [ -f /etc/apk/world ]; then
|
||||||
|
sed -i -E "/^${_pkg}([><= ].*)?$/d" /etc/apk/world 2>/dev/null || true
|
||||||
|
fi
|
||||||
if apk info -e "$_pkg" >/dev/null 2>&1; then
|
if apk info -e "$_pkg" >/dev/null 2>&1; then
|
||||||
apk del "$_pkg" >/dev/null 2>&1 || true
|
apk del "$_pkg" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
if [ "$OPT_KEEP_BINARIES" -eq 0 ]; then
|
||||||
|
for _pkg in sing-box-extended sing-box-tiny; do
|
||||||
|
if [ -f /etc/apk/world ]; then
|
||||||
|
sed -i -E "/^${_pkg}([><= ].*)?$/d" /etc/apk/world 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if apk info -e "$_pkg" >/dev/null 2>&1; then
|
||||||
|
apk del "$_pkg" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ! -f /etc/init.d/sing-box ] || grep -q "Tachyon managed sing-box" /etc/init.d/sing-box 2>/dev/null; then
|
||||||
|
if [ -f /etc/apk/world ]; then
|
||||||
|
sed -i -E '/^sing-box([><= ].*)?$/d' /etc/apk/world 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if apk info -e "sing-box" >/dev/null 2>&1; then
|
||||||
|
apk del "sing-box" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
rm -f /usr/bin/sing-box 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
tui_ok "Пакеты удалены через apk-tools"
|
tui_ok "Пакеты удалены через apk-tools"
|
||||||
elif command -v opkg >/dev/null 2>&1; then
|
elif command -v opkg >/dev/null 2>&1; then
|
||||||
_wait=0
|
_wait=0
|
||||||
|
|||||||
Reference in New Issue
Block a user