Compare commits

...

2 Commits

Author SHA1 Message Date
shaw
f0e89992f7 fix: 使用 setsid 确保重启命令独立于父进程执行
问题原因:
- cmd.Start() 启动的子进程与父进程在同一会话中
- 当 systemctl restart 发送 SIGTERM 给父进程时
- 子进程可能也会被终止,导致重启命令无法完成

修复内容:
- 使用 setsid 创建新会话,子进程完全独立于父进程
- 分离标准输入/输出/错误流
- 确保即使父进程被 kill,重启命令仍能执行完成
2025-12-18 20:00:53 +08:00
shaw
4eaa0cf14a fix: 使用完整路径执行 sudo 和 systemctl 命令
问题原因:
- systemd 服务的 PATH 环境变量可能受限
- 直接使用 "sudo" 可能找不到可执行文件

修复内容:
- 添加 findExecutable 函数动态查找可执行文件路径
- 先尝试 exec.LookPath,再检查常见系统路径
- 添加日志显示实际使用的路径,方便调试
- 兼容不同 Linux 发行版的路径差异
2025-12-18 19:58:25 +08:00

View File

@@ -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,27 @@ 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)
//
// Use setsid to create a new session, ensuring the child process
// survives even if the parent process is killed by systemctl restart
setsidPath := findExecutable("setsid")
cmd := exec.Command(setsidPath, sudoPath, "-n", systemctlPath, "restart", serviceName)
// Detach from parent's stdio to ensure clean separation
cmd.Stdin = nil
cmd.Stdout = nil
cmd.Stderr = nil
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to initiate service restart: %w", err)
}