From 4eaa0cf14a64b0b0114ee49b06435e3fa3953415 Mon Sep 17 00:00:00 2001 From: shaw Date: Thu, 18 Dec 2025 19:58:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=89=A7=E8=A1=8C=20sudo=20=E5=92=8C=20syste?= =?UTF-8?q?mctl=20=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题原因: - systemd 服务的 PATH 环境变量可能受限 - 直接使用 "sudo" 可能找不到可执行文件 修复内容: - 添加 findExecutable 函数动态查找可执行文件路径 - 先尝试 exec.LookPath,再检查常见系统路径 - 添加日志显示实际使用的路径,方便调试 - 兼容不同 Linux 发行版的路径差异 --- backend/internal/pkg/sysutil/restart.go | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/backend/internal/pkg/sysutil/restart.go b/backend/internal/pkg/sysutil/restart.go index 4ccca9d7..a09f5d2e 100644 --- a/backend/internal/pkg/sysutil/restart.go +++ b/backend/internal/pkg/sysutil/restart.go @@ -3,12 +3,39 @@ package sysutil import ( "fmt" "log" + "os" "os/exec" "runtime" ) const serviceName = "sub2api" +// findExecutable finds the full path of an executable +// by checking common system paths +func findExecutable(name string) string { + // First try exec.LookPath (uses current PATH) + if path, err := exec.LookPath(name); err == nil { + return path + } + + // Fallback: check common paths + commonPaths := []string{ + "/usr/bin/" + name, + "/bin/" + name, + "/usr/sbin/" + name, + "/sbin/" + name, + } + + for _, path := range commonPaths { + if _, err := os.Stat(path); err == nil { + return path + } + } + + // Return the name as-is and let exec fail with a clear error + return name +} + // RestartService triggers a service restart via systemd. // // IMPORTANT: This function initiates the restart and returns immediately. @@ -30,10 +57,17 @@ func RestartService() error { log.Println("Initiating service restart...") + // Find full paths for sudo and systemctl + // This ensures the commands work even if PATH is limited in systemd service + sudoPath := findExecutable("sudo") + systemctlPath := findExecutable("systemctl") + + log.Printf("Using sudo: %s, systemctl: %s", sudoPath, systemctlPath) + // The sub2api user has NOPASSWD sudo access for systemctl commands // (configured by install.sh in /etc/sudoers.d/sub2api). // Use -n (non-interactive) to prevent sudo from waiting for password input - cmd := exec.Command("sudo", "-n", "systemctl", "restart", serviceName) + cmd := exec.Command(sudoPath, "-n", systemctlPath, "restart", serviceName) if err := cmd.Start(); err != nil { return fmt.Errorf("failed to initiate service restart: %w", err) }