func monitor(active chan bool, notify chan notification) { for { monitoring := <-active for monitoring { var rusage syscall.Rusage var status syscall.WaitStatus options := syscall.WUNTRACED pid, err := syscall.Wait4(-1, &status, options, &rusage) if err != nil { println("Wait4:", err.Error()) } if pid <= 0 { break } if status.Stopped() { if pid == task0.Job.Group { incoming <- syscall.SIGTSTP } continue } if status.Signaled() { if status.Signal() == syscall.SIGINT && pid == task0.Job.Group { incoming <- syscall.SIGINT } status += 128 } notify <- notification{pid, status} monitoring = <-active } } }
// waitStatusToStateUpdate converts syscall.WaitStatus to a StateUpdate. func waitStatusToStateUpdate(ws syscall.WaitStatus) *stateUpdate { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return newExitedStateUpdate(ok) } return newExitedStateUpdate(newFailure(fmt.Sprint(es))) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return newUnexitedStateUpdate(msg) case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return newUnexitedStateUpdate(msg) case ws.Continued(): return newUnexitedStateUpdate("continued") default: return newUnexitedStateUpdate(fmt.Sprint("unknown status", ws)) } }
func waitForContainerToExit(dir string, containerPid int, signals chan os.Signal) (exitCode int) { for range signals { for { var status syscall.WaitStatus var rusage syscall.Rusage wpid, err := syscall.Wait4(-1, &status, syscall.WNOHANG, &rusage) if err != nil || wpid <= 0 { break // wait for next SIGCHLD } if wpid == containerPid { exitCode = status.ExitStatus() if status.Signaled() { exitCode = 128 + int(status.Signal()) } ioWg.Wait() // wait for full output to be collected check(ioutil.WriteFile(filepath.Join(dir, "exitcode"), []byte(strconv.Itoa(exitCode)), 0700)) return exitCode } } } panic("ran out of signals") // cant happen }
func printStatus(ws syscall.WaitStatus) string { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return "" } return fmt.Sprintf("exited %v", es) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return msg case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return msg case ws.Continued(): return "continued" default: return fmt.Sprintf("unknown status %v", ws) } }
// waitStatusToError converts syscall.WaitStatus to an Error. func waitStatusToError(ws syscall.WaitStatus) error { switch { case ws.Exited(): es := ws.ExitStatus() if es == 0 { return nil } return errors.New(fmt.Sprint(es)) case ws.Signaled(): msg := fmt.Sprintf("signaled %v", ws.Signal()) if ws.CoreDump() { msg += " (core dumped)" } return errors.New(msg) case ws.Stopped(): msg := fmt.Sprintf("stopped %v", ws.StopSignal()) trap := ws.TrapCause() if trap != -1 { msg += fmt.Sprintf(" (trapped %v)", trap) } return errors.New(msg) /* case ws.Continued(): return newUnexitedStateUpdate("continued") */ default: return fmt.Errorf("unknown WaitStatus", ws) } }
func ChildWaitingFunc(pid int, sig chan *ChildWaitData) { var status syscall.WaitStatus var rusage syscall.Rusage result := &ChildWaitData{} for { wpid, err := syscall.Wait4(pid, &status, syscall.WUNTRACED|syscall.WCONTINUED, &rusage) if wpid != pid { continue } if status.Exited() { result.ExitCode = uint32(status.ExitStatus()) break } if status.Stopped() { result.SuccessCode |= EF_STOPPED result.StopSignal = uint32(status.StopSignal()) syscall.Kill(pid, syscall.SIGKILL) } if status.Signaled() { result.SuccessCode |= EF_KILLED_BY_OTHER result.KillSignal = uint32(status.Signal()) break } if err != nil { break } } result.RusageCpuUser = time.Nanosecond * time.Duration(rusage.Utime.Nano()) result.RusageCpuKernel = time.Nanosecond * time.Duration(rusage.Stime.Nano()) sig <- result close(sig) }
func (self *server) Execute(req *pb.ExecutionRequest, resp pb.Builder_ExecuteServer) error { if len(req.Args) == 0 { return fmt.Errorf("Request has no command to execute.") } var args []string if len(req.Args) > 1 { args = req.Args[1:] } if req.BuildEnv == nil { return fmt.Errorf("No build environment present") } else if err := sig.VerifyEnv(req.BuildEnv); err != nil { return fmt.Errorf("Failure verifying build environment: %s", err) } cmd := exec.Command(req.Args[0], args...) cmd.Env = convertEnv(req.GetEnv()) cmd.Stdin = bytes.NewReader(req.Stdin) cmd.Dir = req.BuildEnv.Path glog.V(1).Infof("Commands to execute %v (build dir: %s)", req, cmd.Dir) stdoutPipe, err := cmd.StdoutPipe() if err != nil { return err } stderrPipe, err := cmd.StderrPipe() if err != nil { return err } if err = cmd.Start(); err != nil { return err } streamReader(stdoutPipe, stderrPipe, resp) err = cmd.Wait() var status syscall.WaitStatus if err != nil { if _, ok := err.(*exec.ExitError); ok { status = err.(*exec.ExitError).Sys().(syscall.WaitStatus) } else { return err } } else if cmd.ProcessState != nil { status = cmd.ProcessState.Sys().(syscall.WaitStatus) } s := &pb.Status{ CoreDump: status.CoreDump(), Exited: status.Exited(), ExitStatus: int32(status.ExitStatus()), Signaled: status.Signaled(), Signal: int32(status.Signal()), } resp.Send(&pb.ExecutionResponse{Status: s}) return nil }
func (instance *Execution) runCommand(cmd *exec.Cmd) (values.ExitCode, error) { var waitStatus syscall.WaitStatus if err := cmd.Run(); err != nil { if exitError, ok := err.(*exec.ExitError); ok { waitStatus = exitError.Sys().(syscall.WaitStatus) exitSignal := waitStatus.Signal() if exitSignal > 0 { return values.ExitCode(int(exitSignal) + 128), nil } return values.ExitCode(waitStatus.ExitStatus()), nil } return values.ExitCode(0), UnrecoverableError{error: err} } waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus) return values.ExitCode(waitStatus.ExitStatus()), nil }
func toGuardMode(args []string) { _, pName := path.Split(os.Args[0]) for { pid, err := syscall.ForkExec(args[0], args, nil) if err != nil { log.Fatalf("Error - %s fork failed! [%s]", pName, err.Error()) os.Exit(1) } childPid = pid var ws syscall.WaitStatus _, err = syscall.Wait4(childPid, &ws, 0, nil) for err == syscall.EINTR { _, err = syscall.Wait4(childPid, &ws, 0, nil) } // Log lf, fErr := os.OpenFile("debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if fErr != nil { log.Fatalf("Error - open debug.log failed! [%s]", fErr.Error()) } defer lf.Close() l := log.New(lf, "", os.O_APPEND) if ws.Exited() { l.Printf("[%s] Exited - %s exit status %d", sTime(), pName, ws.ExitStatus()) os.Exit(1) } if ws.Signaled() { l.Printf("[%s] Exited - %s catch signal %d", sTime(), pName, ws.Signal()) } time.Sleep(time.Second * 2) // After release os resouce } }
// ExitStatus returns the correct exit status for a process based on if it // was signaled or exited cleanly func ExitStatus(status syscall.WaitStatus) int { if status.Signaled() { return exitSignalOffset + int(status.Signal()) } return status.ExitStatus() }
func handleSigchld(mpid int) *resultPack { for { var status syscall.WaitStatus var spid int var err error spid, err = syscall.Wait4(-mpid, &status, syscall.WNOHANG|syscall.WALL, nil) if err != nil { poePanic(err, "wait4 failed") } else if spid == 0 { return nil } if spid == mpid && status.Exited() { return &resultPack{POE_SUCCESS, status.ExitStatus(), ""} } else if spid == mpid && status.Signaled() { return &resultPack{POE_SIGNALED, -1, fmt.Sprintf("Program terminated with signal %d (%s)", int(status.Signal()), status.Signal().String())} } else if status.Stopped() { e := status >> 16 & 0xff switch e { case PTRACE_EVENT_SECCOMP: if res := handleSyscall(spid); res != nil { return res } case syscall.PTRACE_EVENT_CLONE, syscall.PTRACE_EVENT_FORK, syscall.PTRACE_EVENT_VFORK: syscall.PtraceCont(spid, 0) default: syscall.PtraceCont(spid, int(status.StopSignal())) } } } }