122 lines
3.4 KiB
Go
122 lines
3.4 KiB
Go
package database
|
||
|
||
import (
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"os/exec"
|
||
"strconv"
|
||
"strings"
|
||
"syscall"
|
||
)
|
||
|
||
const pidFile = "/opt/wg_serf/wg_serf.pid"
|
||
|
||
// CheckAndKillOldProcess проверяет и завершает старый процесс
|
||
func CheckAndKillOldProcess() error {
|
||
// Проверяем существует ли PID файл
|
||
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
|
||
// Файла нет - это первый запуск
|
||
return nil
|
||
}
|
||
|
||
// Читаем PID из файла
|
||
data, err := os.ReadFile(pidFile)
|
||
if err != nil {
|
||
log.Println("⚠️ Не удалось прочитать PID файл:", err)
|
||
return nil
|
||
}
|
||
|
||
oldPID, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
||
if err != nil {
|
||
log.Println("⚠️ Некорректный PID в файле:", err)
|
||
os.Remove(pidFile)
|
||
return nil
|
||
}
|
||
|
||
// Проверяем существует ли процесс
|
||
if !processExists(oldPID) {
|
||
log.Println("📝 Старый процесс не найден, очищаю PID файл")
|
||
os.Remove(pidFile)
|
||
return nil
|
||
}
|
||
|
||
// Проверяем что это действительно wg-panel
|
||
if !isWGPanelProcess(oldPID) {
|
||
log.Println("⚠️ PID принадлежит другому процессу, очищаю файл")
|
||
os.Remove(pidFile)
|
||
return nil
|
||
}
|
||
|
||
// Завершаем старый процесс
|
||
log.Printf("🔄 Обнаружена запущенная версия (PID: %d), завершаю...", oldPID)
|
||
if err := killProcess(oldPID); err != nil {
|
||
return fmt.Errorf("не удалось завершить старый процесс: %v", err)
|
||
}
|
||
|
||
log.Println("✅ Старый процесс завершен")
|
||
os.Remove(pidFile)
|
||
return nil
|
||
}
|
||
|
||
// WritePIDFile записывает PID текущего процесса в файл
|
||
func WritePIDFile() error {
|
||
pid := os.Getpid()
|
||
return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", pid)), 0644)
|
||
}
|
||
|
||
// RemovePIDFile удаляет PID файл
|
||
func RemovePIDFile() {
|
||
os.Remove(pidFile)
|
||
}
|
||
|
||
// processExists проверяет существует ли процесс с данным PID
|
||
func processExists(pid int) bool {
|
||
process, err := os.FindProcess(pid)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
|
||
// Отправляем сигнал 0 для проверки существования процесса
|
||
err = process.Signal(syscall.Signal(0))
|
||
return err == nil
|
||
}
|
||
|
||
// isWGPanelProcess проверяет что процесс действительно wg-panel
|
||
func isWGPanelProcess(pid int) bool {
|
||
// Читаем командную строку процесса
|
||
cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
|
||
if err != nil {
|
||
return false
|
||
}
|
||
|
||
// Проверяем что в командной строке есть wg-panel
|
||
return strings.Contains(string(cmdline), "wg-panel")
|
||
}
|
||
|
||
// killProcess завершает процесс
|
||
func killProcess(pid int) error {
|
||
process, err := os.FindProcess(pid)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// Сначала пробуем мягко (SIGTERM)
|
||
if err := process.Signal(syscall.SIGTERM); err != nil {
|
||
return err
|
||
}
|
||
|
||
// Ждем немного
|
||
cmd := exec.Command("sleep", "1")
|
||
cmd.Run()
|
||
|
||
// Проверяем завершился ли процесс
|
||
if processExists(pid) {
|
||
// Если нет - убиваем принудительно (SIGKILL)
|
||
log.Println("⚠️ Процесс не завершился, использую SIGKILL")
|
||
return process.Signal(syscall.SIGKILL)
|
||
}
|
||
|
||
return nil
|
||
}
|