nginx.go 3.3 KB

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