github.com/immortal/immortal@v0.0.0-20240201195854-d8073cd41019/signals.go (about) 1 package immortal 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "net/http" 8 "os" 9 "strings" 10 "syscall" 11 12 "github.com/nbari/violetear" 13 ) 14 15 // SignalResponse struct to return the error in json format 16 type SignalResponse struct { 17 Err string 18 } 19 20 // HandleSignal send signals to the current process 21 func (d *Daemon) HandleSignal(w http.ResponseWriter, r *http.Request) { 22 var err error 23 24 // get signal from request params 25 signal := violetear.GetParam("*", r) 26 27 if d.process.cmd != nil { 28 switch signal { 29 // a: Alarm. Send the service an ALRM signal. 30 case "a", "alrm", "ALRM": 31 err = d.process.Signal(syscall.SIGALRM) 32 33 // c: Continue. Send the service a CONT signal. 34 case "c", "cont", "CONT": 35 err = d.process.Signal(syscall.SIGCONT) 36 37 // d: Down. If the service is running, send it a TERM signal. After it stops, do not restart it. 38 case "d", "down": 39 d.lockOnce = 1 40 err = d.process.Signal(syscall.SIGTERM) 41 42 // h: Hangup. Send the service a HUP signal. 43 case "h", "hup", "HUP": 44 err = d.process.Signal(syscall.SIGHUP) 45 46 // halt: down + exit 47 // A restart will only happen when using immortaldir 48 case "halt", "restart": 49 d.lockOnce = 1 50 err = d.process.Signal(syscall.SIGTERM) 51 close(d.quit) 52 53 // i: Interrupt. Send the service an INT signal. 54 case "i", "int", "INT": 55 err = d.process.Signal(syscall.SIGINT) 56 57 // in: TTIN. Send the service a TTIN signal. 58 case "in", "ttin", "TTIN": 59 err = d.process.Signal(syscall.SIGTTIN) 60 61 // k: Kill. Send the service a KILL signal. 62 case "k", "kill", "KILL": 63 if d.fpid { 64 err = d.process.Signal(syscall.SIGKILL) 65 } else { 66 err = d.process.Kill() 67 } 68 69 // o: Once. If the service is not running, start it. Do not restart it if it stops. 70 case "o", "once": 71 d.lockOnce = 1 72 if !d.IsRunning(d.process.Pid()) { 73 d.lock = 0 74 d.run <- struct{}{} 75 } 76 77 // ou: TTOU. Send the service a TTOU signal. 78 case "ou", "ttou", "TTOU": 79 err = d.process.Signal(syscall.SIGTTOU) 80 81 // s: stop. Send the service a STOP signal. 82 case "s", "stop", "STOP": 83 err = d.process.Signal(syscall.SIGSTOP) 84 85 // q: QUIT. Send the service a QUIT signal. 86 case "q", "quit", "QUIT": 87 err = d.process.Signal(syscall.SIGQUIT) 88 89 // t: Terminate. Send the service a TERM signal. 90 case "t", "term", "TERM": 91 err = d.process.Signal(syscall.SIGTERM) 92 93 // u: Up. If the service is not running, start it. If the service stops, restart it. 94 case "u", "up", "start": 95 d.lockOnce = 0 96 if !d.IsRunning(d.process.Pid()) { 97 d.lock = 0 98 } 99 d.run <- struct{}{} 100 101 // 1: USR1. Send the service a USR1 signal. 102 case "1", "usr1", "USR1": 103 err = d.process.Signal(syscall.SIGUSR1) 104 105 // 2: USR2. Send the service a USR2 signal. 106 case "2", "usr2", "USR2": 107 err = d.process.Signal(syscall.SIGUSR2) 108 109 // w: WINCH. Send the service a WINCH signal. 110 case "w", "winch", "WINCH": 111 err = d.process.Signal(syscall.SIGWINCH) 112 113 // x: Exit. If you use this option on a stable system, you're doing something wrong. 114 // the supervisor is designed to run forever. 115 case "x", "exit": 116 if d.cfg.cli || os.Getenv("IMMORTAL_EXIT") != "" { 117 close(d.quit) 118 } else { 119 err = fmt.Errorf("set environment variable IMMORTAL_EXIT to exit") 120 } 121 122 default: 123 err = fmt.Errorf("unknown signal: %s", signal) 124 } 125 } else { 126 err = fmt.Errorf("%q not running", strings.Join(d.cfg.command, " ")) 127 } 128 129 res := &SignalResponse{} 130 if err != nil { 131 res.Err = err.Error() 132 log.Printf("signal error: %s\n", err) 133 } 134 135 // return the error on the Response json encoded 136 w.Header().Set("Content-Type", "application/json") 137 if err := json.NewEncoder(w).Encode(res); err != nil { 138 log.Printf("error creating json response: %s\n", err) 139 } 140 }