nginx.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package nginx
  2. import (
  3. "os"
  4. "strconv"
  5. "strings"
  6. "sync"
  7. "time"
  8. "math"
  9. "github.com/0xJacky/Nginx-UI/internal/docker"
  10. "github.com/0xJacky/Nginx-UI/settings"
  11. "github.com/shirou/gopsutil/v4/process"
  12. "github.com/uozi-tech/cosy/logger"
  13. )
  14. var (
  15. mutex sync.Mutex
  16. lastStdOut string
  17. lastStdErr error
  18. )
  19. // TestConfig tests the nginx config
  20. func TestConfig() (stdOut string, stdErr error) {
  21. mutex.Lock()
  22. defer mutex.Unlock()
  23. if settings.NginxSettings.TestConfigCmd != "" {
  24. return execShell(settings.NginxSettings.TestConfigCmd)
  25. }
  26. sbin := GetSbinPath()
  27. if sbin == "" {
  28. return execCommand("nginx", "-t")
  29. }
  30. return execCommand(sbin, "-t")
  31. }
  32. // Reload reloads the nginx
  33. func Reload() (stdOut string, stdErr error) {
  34. mutex.Lock()
  35. defer mutex.Unlock()
  36. // Clear the modules cache when reloading Nginx
  37. clearModulesCache()
  38. if !IsRunning() {
  39. restart()
  40. return
  41. }
  42. if settings.NginxSettings.ReloadCmd != "" {
  43. return execShell(settings.NginxSettings.ReloadCmd)
  44. }
  45. sbin := GetSbinPath()
  46. if sbin == "" {
  47. return execCommand("nginx", "-s", "reload")
  48. }
  49. return execCommand(sbin, "-s", "reload")
  50. }
  51. func restart() {
  52. // fix(docker): nginx restart always output network error
  53. time.Sleep(500 * time.Millisecond)
  54. if settings.NginxSettings.RestartCmd != "" {
  55. lastStdOut, lastStdErr = execShell(settings.NginxSettings.RestartCmd)
  56. return
  57. }
  58. pidPath := GetPIDPath()
  59. daemon := GetSbinPath()
  60. // Check if nginx is running before attempting to stop it
  61. if IsRunning() {
  62. lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
  63. if lastStdErr != nil {
  64. return
  65. }
  66. }
  67. if daemon == "" {
  68. lastStdOut, lastStdErr = execCommand("nginx")
  69. return
  70. }
  71. lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
  72. }
  73. // Restart restarts the nginx
  74. func Restart() {
  75. mutex.Lock()
  76. defer mutex.Unlock()
  77. // Clear the modules cache when restarting Nginx
  78. clearModulesCache()
  79. restart()
  80. }
  81. // GetLastResult returns the last output of the nginx command
  82. func GetLastResult() *ControlResult {
  83. mutex.Lock()
  84. defer mutex.Unlock()
  85. return &ControlResult{
  86. stdOut: lastStdOut,
  87. stdErr: lastStdErr,
  88. }
  89. }
  90. func IsRunning() bool {
  91. pidPath := GetPIDPath()
  92. switch settings.NginxSettings.RunningInAnotherContainer() {
  93. case true:
  94. return docker.StatPath(pidPath)
  95. case false:
  96. return isProcessRunning(pidPath)
  97. }
  98. return false
  99. }
  100. // isProcessRunning checks if the process with the PID from pidPath is actually running
  101. func isProcessRunning(pidPath string) bool {
  102. logger.Debugf("isProcessRunning pidPath: %s", pidPath)
  103. // Check if PID file exists
  104. if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
  105. return false
  106. }
  107. // Read PID from file
  108. pidBytes, err := os.ReadFile(pidPath)
  109. if err != nil {
  110. return false
  111. }
  112. pidStr := strings.TrimSpace(string(pidBytes))
  113. pid, err := strconv.Atoi(pidStr)
  114. if err != nil {
  115. return false
  116. }
  117. // Check that pid is within int32 and positive bounds
  118. if pid <= 0 || pid > math.MaxInt32 {
  119. return false
  120. }
  121. // Use gopsutil for cross-platform process existence check
  122. exists, err := process.PidExists(int32(pid))
  123. if err != nil {
  124. return false
  125. }
  126. if exists {
  127. return true
  128. }
  129. return false
  130. }