| | |
| | | |
| | | import ( |
| | | "analysis/logo" |
| | | "context" |
| | | "os" |
| | | "os/exec" |
| | | "os/signal" |
| | | "syscall" |
| | | "time" |
| | | ) |
| | | |
| | | type procInfo struct { |
| | | cmd *exec.Cmd |
| | | env string |
| | | // ExitInfo info |
| | | type ExitInfo struct { |
| | | Pid int |
| | | ExitCode int |
| | | } |
| | | |
| | | var ( |
| | | procMap = make(map[int]*procInfo) |
| | | ) |
| | | |
| | | func restartProc(ctxt context.Context, pid int) { |
| | | info, ok := procMap[pid] |
| | | if ok { |
| | | err := info.cmd.Wait() |
| | | |
| | | if err != nil { |
| | | logo.Errorln("pid : [", pid, "] quit error: ", err) |
| | | } else { |
| | | logo.Infoln("pid : [", pid, "] quit") |
| | | } |
| | | delete(procMap, pid) |
| | | runProc(ctxt, info.cmd.Path, info.cmd.Args[1:], info.env) |
| | | } else { |
| | | logo.Errorln(pid, " doesn't exist") |
| | | } |
| | | } |
| | | |
| | | func quitProc(pid int) { |
| | | info, ok := procMap[pid] |
| | | if ok { |
| | | delete(procMap, pid) |
| | | |
| | | syscall.Kill(pid, syscall.SIGINT) |
| | | info.cmd.Wait() |
| | | } else { |
| | | logo.Errorln(pid, " doesn't exist") |
| | | } |
| | | } |
| | | func runProc(ctxt context.Context, bin string, args []string, env string) (int, error) { |
| | | cmd := exec.CommandContext(ctxt, bin, args...) |
| | | rEnv := "" |
| | | if len(env) != 0 { |
| | | runtime := "LD_LIBRARY_PATH" |
| | | rEnv = runtime + "=" + env |
| | | logo.Infoln("Env String: ", rEnv) |
| | | |
| | | // remove os environ ld |
| | | old := os.Getenv(runtime) |
| | | os.Unsetenv(runtime) |
| | | cmd.Env = os.Environ() |
| | | cmd.Env = append(cmd.Env, rEnv) |
| | | os.Setenv(runtime, old) |
| | | } |
| | | |
| | | pid := -1 |
| | | cmd.Stdout = os.Stdout |
| | | cmd.Stderr = os.Stderr |
| | | cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGTERM} |
| | | |
| | | err := cmd.Start() |
| | | if err == nil { |
| | | pid = cmd.Process.Pid |
| | | procMap[pid] = &procInfo{cmd, env} |
| | | } |
| | | return pid, err |
| | | } |
| | | |
| | | // Config conf |
| | | // Config config |
| | | type Config struct { |
| | | Pid int |
| | | Options int |
| | |
| | | func sigChildHandler(notifications chan os.Signal) { |
| | | sigs := make(chan os.Signal, 3) |
| | | signal.Notify(sigs, syscall.SIGCHLD) |
| | | signal.Ignore(syscall.SIGPIPE) |
| | | |
| | | for { |
| | | sig := <-sigs |
| | |
| | | } /* End of function sigChildHandler. */ |
| | | |
| | | // Be a good parent - clean up behind the children. |
| | | func reapChildren(config Config, pidChan chan<- int) { |
| | | func reapChildren(config Config, info chan<- ExitInfo) { |
| | | notifications := make(chan os.Signal, 1) |
| | | |
| | | go sigChildHandler(notifications) |
| | |
| | | * Plants vs. Zombies!! |
| | | */ |
| | | pid, err := syscall.Wait4(pid, &wstatus, opts, nil) |
| | | pidChan <- pid |
| | | info <- ExitInfo{pid, wstatus.ExitStatus()} |
| | | for syscall.EINTR == err { |
| | | pid, err = syscall.Wait4(pid, &wstatus, opts, nil) |
| | | pidChan <- pid |
| | | info <- ExitInfo{pid, wstatus.ExitStatus()} |
| | | } |
| | | |
| | | if syscall.ECHILD == err { |
| | |
| | | // background inside a goroutine. |
| | | |
| | | // Reap reap |
| | | func Reap(pidChan chan<- int) { |
| | | func Reap(info chan<- ExitInfo) { |
| | | /* |
| | | * Only reap processes if we are taking over init's duties aka |
| | | * we are running as pid 1 inside a docker container. The default |
| | |
| | | Pid: -1, |
| | | Options: 0, |
| | | DisablePid1Check: true, |
| | | }, pidChan) |
| | | }, info) |
| | | |
| | | } /* End of [exported] function Reap. */ |
| | | |
| | |
| | | // The child processes are reaped in the background inside a goroutine. |
| | | |
| | | // Start start |
| | | func Start(config Config, pidChan chan<- int) { |
| | | func Start(config Config, info chan<- ExitInfo) { |
| | | /* |
| | | * Start the Reaper with configuration options. This allows you to |
| | | * reap processes even if the current pid isn't running as pid 1. |
| | |
| | | * of 'em all, either way we get to play the grim reaper. |
| | | * You will be missed, Terry Pratchett!! RIP |
| | | */ |
| | | go reapChildren(config, pidChan) |
| | | go reapChildren(config, info) |
| | | |
| | | } /* End of [exported] function Start. */ |
| | | |
| | | func waitForRestart(ctxt context.Context, pidChan <-chan int) { |
| | | |
| | | for { |
| | | select { |
| | | case <-ctxt.Done(): |
| | | return |
| | | case pid := <-pidChan: |
| | | restartProc(ctxt, pid) |
| | | default: |
| | | time.Sleep(3 * time.Second) |
| | | } |
| | | } |
| | | } |