Files
NeoTachyon/tachyon/files/usr/lib/core/packages.uc
T
Dushnilin 488bbfefd5 fix: комплексный аудит и исправление ucode кодовой базы
Критические исправления:
- safe_proxy_restart: удаление lock-файла после фонового перезапуска
  с защитой от stale lock (>300 сек)
- write_json_file: атомарная запись через tmp+mv вместо прямой
- write_reload_state: атомарная запись через tmp+mv
- state_add_list: отклонение значений с пробелами

Исправления безопасности:
- killall logread заменён на pkill -f 'logread -f'
- SIGTERM→SIGKILL для Telegram и sing-box при остановке
- Recover OOM scale: инкремент +0.05 каждые 10 минут
- nfqueue и byedpi: trap для корректного завершения дочерних процессов
- nfqueue: валидация стратегий и откат при ошибке запуска
- nfqueue: flush mangle_output перед добавлением правил
- Исправлен парсинг exit code в 14 файлах (status & 127)

Улучшения стабильности:
- init.d: trap для start_service/stop_service
- watchdog: signal traps для legacy fallback loop
- lifecycle: логирование ошибок при остановке компонентов
- singbox/priority: SIGTERM→SIGKILL при остановке
- telegram: exponential backoff (1x→300s) при ошибках API
- telegram: process_updates возвращает boolean для отслеживания успеха
- watchdog: кэш proxy port для уменьшения чтения конфига sing-box
- singbox/generator: упрощён atomic_write_json_file
- packages.uc: переупорядочивание apk_version (лёгкие запросы первыми)
- dns/apply: проверка PID sing-box перед настройкой dnsmasq
- server/service: cleanup_orphaned_server_certs перед вызовом
2026-08-06 00:03:51 +03:00

217 lines
6.0 KiB
Ucode

#!/usr/bin/env ucode
let fs = require("fs");
function as_string(value) {
return value == null ? "" : "" + value;
}
function shell_quote(value) {
return "'" + replace(as_string(value), /'/g, "'\\''") + "'";
}
function command_from_args(args) {
let parts = [];
for (let arg in args)
push(parts, shell_quote(arg));
return join(" ", parts);
}
function command_success(args) {
return system(command_from_args(args) + " >/dev/null 2>&1") == 0;
}
function command_output(args) {
let pipe = fs.popen(command_from_args(args), "r");
if (!pipe)
return "";
let data = pipe.read("all");
let status = pipe.close();
if (status != 0 || data == null)
return "";
return as_string(data);
}
function command_exists(name) {
return command_success([ "command", "-v", name ]);
}
function apk_installed(package_name) {
return command_exists("apk") && command_success([ "apk", "info", "-e", as_string(package_name) ]);
}
function opkg_installed(package_name) {
package_name = as_string(package_name);
if (!command_exists("opkg"))
return false;
let prefix = package_name + " - ";
for (let line in split(command_output([ "opkg", "list-installed" ]), "\n")) {
line = trim(as_string(line));
if (substr(line, 0, length(prefix)) == prefix)
return true;
}
return false;
}
function installed(package_name) {
return apk_installed(package_name) || opkg_installed(package_name);
}
function apk_manifest_version(package_name, output) {
package_name = as_string(package_name);
let found = false;
for (let line in split(as_string(output), "\n")) {
line = trim(as_string(line));
if (substr(line, 0, 2) == "P:")
found = substr(line, 2) == package_name;
else if (found && substr(line, 0, 2) == "V:")
return substr(line, 2);
}
return "";
}
function apk_info_version(package_name, output) {
package_name = as_string(package_name);
let prefix = package_name + "-";
for (let line in split(as_string(output), "\n")) {
line = trim(as_string(line));
if (line == "")
continue;
if (substr(line, 0, length(prefix)) == prefix)
return substr(line, length(prefix));
}
return "";
}
function apk_list_version(package_name, output) {
package_name = as_string(package_name);
let prefix = package_name + "-";
for (let line in split(as_string(output), "\n")) {
for (let field in split(trim(as_string(line)), /[ \t]+/)) {
field = as_string(field);
if (substr(field, 0, length(prefix)) != prefix)
continue;
let version = substr(field, length(prefix));
if (version != "")
return version;
}
}
return "";
}
function apk_query_version(package_name, output) {
package_name = as_string(package_name);
let packages;
try {
packages = json(as_string(output));
}
catch (e) {
return "";
}
if (type(packages) != "array")
return "";
for (let package in packages) {
if (type(package) != "object" || as_string(package.name) != package_name)
continue;
let version = as_string(package.version);
if (version != "")
return version;
}
return "";
}
function apk_version(package_name) {
package_name = as_string(package_name);
if (!apk_installed(package_name))
return "";
let version = apk_list_version(package_name, command_output([ "apk", "list", "--installed", package_name ]));
if (version != "")
return version;
version = apk_info_version(package_name, command_output([ "apk", "info", "-v", package_name ]));
if (version != "")
return version;
version = apk_manifest_version(package_name, command_output([ "apk", "list", "--installed", "--manifest", package_name ]));
if (version != "")
return version;
return apk_manifest_version(package_name, command_output([ "apk", "list", "--installed", "--manifest" ]));
}
function apk_available_version(package_name) {
package_name = as_string(package_name);
if (!command_exists("apk"))
return "";
return apk_query_version(
package_name,
command_output([ "apk", "query", "--from", "repositories", "--available", "--format", "json", "--fields", "name,version", package_name ])
);
}
function opkg_version(package_name) {
package_name = as_string(package_name);
if (!command_exists("opkg"))
return "";
let prefix = package_name + " - ";
for (let line in split(command_output([ "opkg", "list-installed" ]), "\n")) {
line = trim(as_string(line));
if (substr(line, 0, length(prefix)) == prefix)
return substr(line, length(prefix));
}
return "";
}
function version(package_name) {
let value = apk_version(package_name);
return value != "" ? value : opkg_version(package_name);
}
function module_exports() {
return {
installed: installed,
apk_installed: apk_installed,
opkg_installed: opkg_installed,
version: version,
installed_package_version: version,
apk_version: apk_version,
apk_available_version: apk_available_version,
opkg_version: opkg_version
};
}
if (sourcepath(1) != null && sourcepath(1) != "")
return module_exports();
let mode = ARGV[0] || "";
if (mode == "installed")
exit(installed(ARGV[1]) ? 0 : 1);
else if (mode == "apk-installed")
exit(apk_installed(ARGV[1]) ? 0 : 1);
else if (mode == "opkg-installed")
exit(opkg_installed(ARGV[1]) ? 0 : 1);
else if (mode == "version")
print(version(ARGV[1]), "\n");
else if (mode == "apk-version")
print(apk_version(ARGV[1]), "\n");
else if (mode == "apk-available-version")
print(apk_available_version(ARGV[1]), "\n");
else if (mode == "opkg-version")
print(opkg_version(ARGV[1]), "\n");
else {
warn("Usage: core/packages.uc <installed|apk-installed|opkg-installed|version|apk-version|apk-available-version|opkg-version> <package>\n");
exit(1);
}