func (cmd *Cmd) Kill() error { switch cmd.State { case Running: cmd.State = Terminated lg.Debugf("Cmd:\tKilling %v\n", cmd.JobID) pgid, err := syscall.Getpgid(cmd.Cmd.Process.Pid) if err != nil { // Fall-back on error. Kill the main process only. cmd.Cmd.Process.Kill() break } // Kill the whole process group. syscall.Kill(-pgid, 15) case Finished: lg.Debug("Cmd:\tKilling pgroup %v\n", cmd.JobID) pgid, err := syscall.Getpgid(cmd.Cmd.Process.Pid) if err != nil { break } // Make sure to kill the whole process group, // so there are no subprocesses left. syscall.Kill(-pgid, 15) case Initialized: // This one is tricky, as the cmd's Start() might have // been called and is already in progress, but the cmd's // state is not Running yet. usCallingStartOnce := false cmd.StartOnce.Do(func() { cmd.WaitOnce.Do(func() { cmd.State = Invalidated cmd.StatusCode = -2 cmd.Err = errors.New("invalidated") lg.Debugf("Cmd: Invalidating %v\n", cmd.JobID) close(cmd.Finished) }) close(cmd.Started) usCallingStartOnce = true }) if !usCallingStartOnce { // It was cmd.Start() that called StartOnce.Do(), not us, // thus we need to wait for Started and try to Kill again: <-cmd.Started cmd.Kill() } } return cmd.Err }
func (p *execProcess) Start() error { if p.cmd.Stdout == nil { p.cmd.Stdout = p.stdoutWriter } if p.cmd.Stderr == nil { p.cmd.Stderr = p.stderrWriter } cmdString := strings.Join(p.cmd.Args, " ") p.logger.Debug(execProcessLogTag, "Running command '%s'", cmdString) if !p.keepAttached { p.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} } err := p.cmd.Start() if err != nil { return bosherr.WrapErrorf(err, "Starting command '%s'", cmdString) } if !p.keepAttached { p.pgid = p.cmd.Process.Pid } else { p.pgid, err = syscall.Getpgid(p.pid) if err != nil { p.logger.Error(execProcessLogTag, "Failed to retrieve pgid for command '%s'", cmdString) p.pgid = -1 } } return nil }
func (r *Runner) Kill() error { pgid, err := syscall.Getpgid(r.cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, syscall.SIGTERM) } return err }
func (k *PosixKernel) Getpgid(pid int) uint64 { n, err := syscall.Getpgid(pid) if err != nil { return Errno(err) } return uint64(n) }
//KillGroupProcess ... func killGroupProcess(cmd *exec.Cmd) { pgid, err := syscall.Getpgid(cmd.Process.Pid) if err == nil { err = syscall.Kill(-pgid, 15) printError("syscall Kill :", err) sendMessage("info", "Run aborted\n") } }
// Satisfies the Listener interface and calls the relevant binary file func (this *Cli) Exec(evt event.Event) { this.Log.Handler(this, &evt) bin := magicString(this.Config.GetBin(), evt) stdin := magicString(this.Config.GetStdin(), evt) args := append([]string(nil), this.Config.GetArgs()...) for i, arg := range this.Config.GetArgs() { args[i] = magicString(arg, evt) } cmd := exec.Command(bin, args...) cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Stdin = strings.NewReader(stdin) var out bytes.Buffer var sErr bytes.Buffer cmd.Stdout = &out cmd.Stderr = &sErr this.Log.Info("CLI CMD %s %s \"%s %s\"", evt.GetId(), this.GetName(), bin, strings.Join(args, " ")) err := cmd.Start() if err != nil { this.Log.Error("CLI ERR %s %s \"%s\"", evt.GetId(), this.GetName(), sErr.String()) this.Log.HandlerError(this, err.Error(), &evt) return } timeOut := this.Config.GetTimeout() if timeOut == 0 { if err := cmd.Wait(); err != nil { this.Log.Error("CLI ERROR %s", err.Error()) } } else { // this allows us to set a timeout on the cli (phantomjs def needs this) done := make(chan error, 1) go func() { done <- cmd.Wait() }() select { case <-time.After(time.Duration(timeOut) * time.Second): pgid, err := syscall.Getpgid(cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, 15) // note the minus sign this.Log.Warning("CLITIMEOUT %s %s", evt.GetId(), this.GetName()) } <-done // allow goroutine to exit case err := <-done: if err != nil { this.Log.Error("CLI ERROR %s", err.Error()) } } } this.Log.Debug("CLI OUT %s %s \"%s\"", evt.GetId(), this.GetName(), out.String()) }
func (c *command) Info() (pid, pgrp int) { pid = c.proc.Process.Pid pgrp, err := syscall.Getpgid(pid) if err != nil { c.test.Fatal(err) } return }
func killall(multierr io.Writer, cmd *exec.Cmd) { cmd.Start() pgid, err := syscall.Getpgid(cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, 15) // note the minus sign cmd.Wait() } else { fmt.Fprintf(multierr, "\n%v\n", err) } }
func sendSignalToProcess(process *os.Process, what values.Signal, tryGroup bool) error { if tryGroup { pgid, err := syscall.Getpgid(process.Pid) if err == nil { if syscall.Kill(-pgid, syscall.Signal(what)) == nil { return nil } } } process.Signal(syscall.Signal(what)) return nil }
// Kill a script run and all child processes func (self *ScriptRun) kill() error { if self.Cmd == nil { return errors.New("Cmd is nil") } else if self.Cmd.Process == nil { return errors.New("Cmd.Process is nil") } pgid, err := syscall.Getpgid(self.Cmd.Process.Pid) if err != nil { return err } return syscall.Kill(-pgid, syscall.SIGKILL) }
// kills a cmd process based on config timeout settings func killProcessOnTimeout(cmd *exec.Cmd, timeout time.Duration) (exitCode int, err error) { // 1 deep channel for done done := make(chan error, 1) go func() { done <- cmd.Wait() }() processGroupID, err := syscall.Getpgid(cmd.Process.Pid) if err != nil { return 0, err } grimProcessGroupID, err := syscall.Getpgid(os.Getpid()) if err != nil { return 0, err } select { case <-time.After(timeout): exitCode = -23 err = errTimeout case err := <-done: if err != nil { exitCode, err = getExitCode(err) if err != nil { return 0, fmt.Errorf("Build Error: %v", err) } } } if grimProcessGroupID != processGroupID { syscall.Kill(-processGroupID, syscall.SIGKILL) } return }
func TestIPERF(t *testing.T) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) signal.Notify(c, syscall.SIGTERM) go func() { if <-c != syscall.SIGTERM { panic(nil) } }() if len(os.Getenv("IPERF")) != 0 { cmd0 := exec.Command("iperf3", "-s", "", "-p", "5203") cmd0.Start() pid := cmd0.Process.Pid go cmd0.Wait() t0 := Accelerate("tcp://:41501-41504,udp://:42401-42404", "tcp://127.0.0.1:5203", BACKEND) t0.WaitforAlive() t1 := Accelerate("tcp://:50500", "tcp://127.0.0.1:41501-41504,udp://127.0.0.1:42401-42404", FRONTEND) t1.WaitforAlive() //iperfExec(exec.Command("iperf3", "-c", "127.0.0.1", "-p", "50500", "-R", "-P", "3")) //iperfExec(exec.Command("iperf3", "-c", "127.0.0.1", "-p", "50500", "-b", "10M")) cmd1 := exec.Command("iperf3", "-c", "127.0.0.1", "-p", "50500", "--get-server-output") iperfExec(cmd1) if len(os.Getenv("CPU")) != 0 { f, err := os.Create("cpu.profile") if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } cmd1.Wait() cmd2 := exec.Command("iperf3", "-c", "127.0.0.1", "-p", "50500", "-R", "--get-server-output") iperfExec(cmd2) cmd2.Wait() t0.Status() t1.Status() pgid, err := syscall.Getpgid(pid) if err == nil { syscall.Kill(-pgid, 15) // note the minus sign } } }
func killall(multierr io.Writer, cmd *exec.Cmd) { pgid, err := syscall.Getpgid(cmd.Process.Pid) // don't kill myself if cmd is running in same process group if pgid == os.Getpid() || pgid == os.Getgid() { cmd.Process.Kill() return } if err == nil { syscall.Kill(-pgid, 15) // note the minus sign cmd.Wait() } else { fmt.Fprintf(multierr, "\n%v\n", err) } }
func (x *ProcessManager) KillProcesses() error { x.processes.Lock() defer x.processes.Unlock() for _, pi := range x.processes.values { // we could potentially fail before the processes are correctly started // in that case, do nothing if pi.cmd.Process != nil { pgid, err := syscall.Getpgid(pi.cmd.Process.Pid) if err != nil { return err } syscall.Kill(-pgid, 15) } } return nil }
func (i *instance) cmdKill(req *Request) (*Response, error) { glog.Infoln("Server going down with SIGKILL") glog.Flush() pgid, err := syscall.Getpgid(0) if err != nil { glog.Errorln("Failed to get pgid", err) os.Exit(1) } err = syscall.Kill(-pgid, syscall.SIGKILL) if err != nil { glog.Errorln("Failed to kill our process group", err) os.Exit(1) } // We'll never get here... return nil, nil }
func fg(ec *EvalCtx, pids ...int) { if len(pids) == 0 { throw(ErrArgs) } var thepgid int for i, pid := range pids { pgid, err := syscall.Getpgid(pid) maybeThrow(err) if i == 0 { thepgid = pgid } else if pgid != thepgid { throw(ErrNotInSameGroup) } } err := sys.Tcsetpgrp(0, thepgid) maybeThrow(err) errors := make([]Error, len(pids)) for i, pid := range pids { err := syscall.Kill(pid, syscall.SIGCONT) if err != nil { errors[i] = Error{err} } } for i, pid := range pids { if errors[i] != OK { continue } var ws syscall.WaitStatus _, err = syscall.Wait4(pid, &ws, syscall.WUNTRACED, nil) if err != nil { errors[i] = Error{err} } else { // TODO find command name errors[i] = Error{NewExternalCmdExit(fmt.Sprintf("(pid %d)", pid), ws, pid)} } } throwCompositeError(errors) }
// isLeader determines, whether g is still the leader of the process group func (g *Group) isLeader() (ok bool, err error) { if g == nil { return false, syscall.ESRCH } pgid, err := syscall.Getpgid(g.pid) if err != nil { return false, err } // Pids 0 and 1 will have special meaning, so don't return them. if pgid < 2 { return false, nil } // the process is not the leader? if pgid != g.pid { return false, nil } return true, nil }
// This should only be called from within the Runnable // which ensures that the process has started and so can be killed func (cmd *Cmd) Kill(proc chan error) { log.Info("Sending signal SIGTERM to command:", cmd.Name) pgid, err := syscall.Getpgid(cmd.Process.Pid) if err != nil { if err.Error() == "no such process" { log.Info("Process exited before SIGTERM:", cmd.Name) } else { log.Err("Error getting process group:", err) } return } if err := syscall.Kill(-pgid, syscall.SIGTERM); err != nil { log.Warn("Failed to send SIGTERM, command must have exited (name, error):", cmd.Name, err) return } // give process time to exit… timerDone := make(chan struct{}) timer := time.AfterFunc(time.Duration(*exitWait)*time.Millisecond, func() { close(timerDone) }) select { case <-timerDone: case <-proc: timer.Stop() return } log.Info("After exitwait, command still running, sending SIGKILL…") if err := syscall.Kill(-pgid, syscall.SIGKILL); err != nil { if err.Error() == "no such process" { log.Info("Process exited before SIGKILL:", cmd.Name) } else { log.Err("Error killing command (cmd, error):", cmd.Name, err) } } }
func (sc *ServiceConfig) stopProcess(cfg OperationConfig, command *ServiceCommand, graceful bool) (success bool, err error) { pgid, err := syscall.Getpgid(command.Pid) if err != nil { return false, errors.WithStack(err) } if pgid == 0 || pgid == 1 { return false, errors.WithStack(errors.New("suspect pgid: " + strconv.Itoa(pgid))) } err = command.killGroup(cfg, pgid, graceful) if err != nil { return false, errors.WithStack(err) } // Check to see if the process is still running exists, err := process.PidExists(int32(command.Pid)) if err != nil { return false, errors.WithStack(err) } return !exists, nil }
func terminateProc(proc string) error { p := procs[proc].cmd.Process if p == nil { return nil } pgid, err := syscall.Getpgid(p.Pid) if err != nil { return err } // use pgid, ref: http://unix.stackexchange.com/questions/14815/process-descendants pid := p.Pid if pgid == p.Pid { pid = -1 * pid } target, err := os.FindProcess(pid) if err != nil { err = target.Signal(syscall.SIGHUP) } return err }
func (r *ConcreteCmdRunner) Run(command string, args ...string) error { cmd := exec.Command(command, args...) cmd.Stdout = r.Stdout cmd.Stderr = r.Stderr cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} if err := cmd.Start(); err != nil { return err } timer := time.AfterFunc(r.Timeout, func() { pgid, err := syscall.Getpgid(cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, 15) } }) err := cmd.Wait() if !timer.Stop() { return &TimeoutError{} } return err }
// ProcessGroup determines the process group of p and if we are their leader func ProcessGroup(p *os.Process) (grp *os.Process, err error) { if p == nil { return nil, syscall.ESRCH } pgid, err := syscall.Getpgid(p.Pid) if err != nil { return nil, err } // Pids 0 and 1 will have special meaning, so don't return them. if pgid < 2 { return nil, ErrNotLeader } // the process is not the leader? if pgid != p.Pid { return nil, ErrNotLeader } // This just creates a process object from a Pid in Unix // instead of actually searching it. grp, err = os.FindProcess(-pgid) return grp, err }
// NewControlledProcess creates the child proc. func NewControlledProcess(cmd string, arguments []string, doneChan chan error, stdoutLimit int64) (JobControl, error) { var err error j := &Job{ nil, nil, 0, 0, doneChan, stdoutLimit, nil, } // Drop command from cmdline arguments and pass the rest as arguments separately var args []string if len(arguments) > 0 { args = arguments[1:] } j.Cmd = exec.Command(cmd, args...) // Collect stdout from the process to redirect to real stdout stdoutpipe, err := j.Cmd.StdoutPipe() if err != nil { return nil, fmt.Errorf("Failed to acquire stdout: %s", err) } stdout := iocontrol.NewMeasuredReader(stdoutpipe) j.stdoutReader = stdout var wg sync.WaitGroup stdin, err := j.Cmd.StdinPipe() if err != nil { return nil, fmt.Errorf("Failed to acquire stdin: %s", err) } stderr, err := j.Cmd.StderrPipe() if err != nil { return nil, fmt.Errorf("Failed to acquire stderr: %s", err) } // Map all child processes under this tree so Kill really ends everything. j.Cmd.SysProcAttr = &syscall.SysProcAttr{ Setpgid: true, // Set process group ID } log.Debugf("%#v\n", j.Cmd) // Start the sub-process but don't wait for completion to pickup the Pid // for resource monitoring. err = j.Cmd.Start() if err != nil { return nil, fmt.Errorf("Failed to execute sub-process: %s\n", err) } j.Pid = j.Cmd.Process.Pid j.Pgid, err = syscall.Getpgid(j.Pid) if err != nil { return nil, fmt.Errorf("Failed syscall.Getpgid: %s\n", err) } j.Proc, err = process.NewProcess(int32(j.Pgid)) if err != nil { return nil, fmt.Errorf("Unable to create process.NewProcess: %s\n", err) } wg.Add(1) go func(wg *sync.WaitGroup, r io.Reader) { defer wg.Done() io.Copy(os.Stdout, r) log.Debugln("child closed stdout") }(&wg, stdout) go func(w io.WriteCloser) { io.Copy(w, os.Stdin) }(stdin) wg.Add(1) go func(wg *sync.WaitGroup, r io.Reader) { defer wg.Done() io.Copy(os.Stderr, r) log.Debugln("child closed stderr") }(&wg, stderr) // Background waiting for the job to finish and emit a done channel message // when complete. go func(wg *sync.WaitGroup, j *Job) { log.Debugln("Waiting on wg.Wait()") wg.Wait() log.Debugln("Waiting on Cmd.Wait()") err := j.Cmd.Wait() log.Debugf("Job finished: %q\n", err) j.done <- err }(&wg, j) return j, nil }
/* Execute a command (using arguments 'args') Redirect stdout to outFile (unless file name is empty) Redirect stderr to errFile (unless file name is empty) Write exit code to exitFile (unless file name is empty) Timeout after timeout seconds (unless time is zero) */ func (be *BdsExec) executeCommand() int { if DEBUG { log.Printf("Debug, executeCommand %s\n", be.command) } // Redirect all signals to channel (e.g. Ctrl-C) osSignal := make(chan os.Signal) if be.taskLoggerFile != "" { // Main bds program signal.Notify(osSignal) // Capture all signals } else { // Set a new process group. // We want to be able to kill all child processes, without killing the // calling program. E.g. When running using a local executor, the Java Bds // calls 'bds exec', so sending a kill to the group when a timeOut occurs, // would also kill the parent Java program and kill the whole bds execution // (clearly not what we want). // To avoid this, we create a new group thus we can send a kill signal to // this new process group. gpidOri, _ := syscall.Getpgid(0) if err := syscall.Setpgid(0, 0); err != nil { // During an ssh remote execution we will no be albe to do this. // In this case, we assume that the SSH daemon will catch the sinals // and kill al child processes. if DEBUG { log.Printf("Error setting process group: %s", err) } } if DEBUG { gpidNew, _ := syscall.Getpgid(0) log.Printf("Info: Setting new process group. Original GPID: %d, new GPID: %d\n", gpidOri, gpidNew) } } // Create command be.cmd = exec.Command(be.command) be.cmd.Args = be.cmdargs // Copy stdout stdout := tee.NewTee(be.outFile, false) defer stdout.Close() be.cmd.Stdout = stdout // Copy stderr stderr := tee.NewTee(be.errFile, true) defer stderr.Close() be.cmd.Stderr = stderr // Connect to stdin be.cmd.Stdin = os.Stdin // Start process err := be.cmd.Start() if err != nil { log.Fatal(err) } be.exitCode = be.executeCommandTimeout(osSignal) if DEBUG { log.Printf("Debug, executeCommand: Exit code %d\n", be.exitCode) } return be.exitCode }
func (cr *ConsoleRunner) handleConsoleRunnerRun(b core.Bot, m *slack.Message) error { messageWithoutMentions := util.TrimWhitespace(core.LessSpecificMention(m.Text, b.ID())) cleanedMessage := core.FixLinks(messageWithoutMentions) pieces := strings.Split(cleanedMessage, " ") if len(pieces) < 2 { return exception.Newf("invalid arguments for `%s`", ActionConsoleRunnerRun) } commandWithArguments := pieces[1:] command := commandWithArguments[0] args := []string{} if len(commandWithArguments) > 1 { args = commandWithArguments[1:] } if !cr.isWhitelistedCommand(command) { return exception.Newf("`%s` cannot run %s", ActionConsoleRunnerRun, command) } cmdFullPath, lookErr := exec.LookPath(command) if lookErr != nil { return exception.Wrap(lookErr) } stdoutBuffer := bytes.NewBuffer([]byte{}) subCmd := exec.Command(cmdFullPath, args...) subCmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} subCmd.StdoutPipe() subCmd.StderrPipe() subCmd.Stdout = stdoutBuffer subCmd.Stderr = stdoutBuffer startErr := subCmd.Start() if startErr != nil { return startErr } started := time.Now().UTC() didTimeout := false go func() { for { now := time.Now().UTC() if now.Sub(started) > ConsoleRunnerTimeout { didTimeout = true pgid, err := syscall.Getpgid(subCmd.Process.Pid) if err != nil { return } syscall.Kill(-pgid, 15) } time.Sleep(50 * time.Millisecond) } }() subCmd.Wait() timedOutText := "" if didTimeout { timedOutText = " (timed out)" } stdout := stdoutBuffer.String() outputText := fmt.Sprintf("console runner stdout%s:\n", timedOutText) if len(stdout) != 0 { prefixed := strings.Replace(stdout, "\n", "\n>", -1) outputText = outputText + fmt.Sprintf(">%s", prefixed) } else { outputText = "> empty" } return b.Say(m.Channel, outputText) }
//Execute a command by specifying executable and arguments, returns statuscode and output summary func Execute(timeout int, cmdName string, cmdArgs ...string) (status int, output string) { // TODO: Check if cmdName file exists cmd := exec.Command(cmdName, cmdArgs...) cmdOutput := &bytes.Buffer{} errOutput := &bytes.Buffer{} fail := false killed := false cmd.Stdout = cmdOutput cmd.Stderr = errOutput var waitStatus syscall.WaitStatus cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} cmd.Start() timer := time.AfterFunc(time.Duration(timeout+1)*time.Second, func() { if cmd.Process != nil { pgid, err := syscall.Getpgid(cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, 9) // note the minus sign log.Notice("Killed PID", pgid, "because of timeout of ", timeout, "seconds while running", cmdName) killed = true } } else { log.Error("Tried to kill but it didn't exist (anymore).", cmdName, cmdArgs) } }) if err := cmd.Wait(); err != nil { if err != nil { fail = true } if exitError, ok := err.(*exec.ExitError); ok { waitStatus = exitError.Sys().(syscall.WaitStatus) } } else { // Success waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus) } if killed { return killedStatus() } timer.Stop() outputString := string(cmdOutput.Bytes()) shortOutputStrings := strings.Split(outputString, "\n") statusCode := waitStatus.ExitStatus() if waitStatus.ExitStatus() == -1 { return killedStatus() } if waitStatus.ExitStatus() == 0 && fail { statusCode = 420 } return statusCode, shortOutputStrings[0] }
func (su *Supervise) KillProc() { var pgid, err = syscall.Getpgid(su.pid) if err == nil { syscall.Kill(-pgid, syscall.SIGKILL) } }
func getPgID(cmd *exec.Cmd) (int, error) { return syscall.Getpgid(cmd.Process.Pid) }
// Run command, maar onderbreek het als chKill of chGlobalExit gesloten is func run(cmd *exec.Cmd, chKill chan bool, chPipe chan string) error { cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} chRet := make(chan error, 2) // deze functie schrijft twee keer op chRet go func() { if chPipe == nil { cmd.Start() chRet <- nil err := cmd.Wait() chRet <- err return } pipe, err := cmd.StdoutPipe() if err != nil { chRet <- nil chRet <- err return } cmd.Start() chRet <- nil var err1, err2 error rd := util.NewReader(pipe) for { var line string line, err1 = rd.ReadLineString() if err1 == io.EOF { err1 = nil break } if err1 != nil { break } chPipe <- line } close(chPipe) err2 = cmd.Wait() if err1 != nil { chRet <- err1 } else { chRet <- err2 } }() <-chRet // commando is gestart pgid, err := syscall.Getpgid(cmd.Process.Pid) if err != nil { // misschien betekent een fout alleen maar dat het process net klaar is logf("BIG TROUBLE: syscall.Getpgid(cmd.Process.Pid) error: %v", err) pgid = 0 } FORSELECT: for { select { case err = <-chRet: return err case <-chGlobalExit: break FORSELECT case <-chKill: break FORSELECT } } for _, sig := range []int{15, 9} { err = syscall.Kill(-pgid, syscall.Signal(sig)) if err != nil { logf("syscall.Kill(-pgid, %d) error: %v", sig, err) } if sig != 9 { time.Sleep(2 * time.Second) } } err = <-chRet return err }
// KillProcess kills the new process created by StartNewProcess // It kills the whole process group to ensure // all of its child processes are killed func (w *watch) KillProcess() { pgid, err := syscall.Getpgid(w.cmd.Process.Pid) if err == nil { syscall.Kill(-pgid, syscall.SIGTERM) } }