Beispiel #1
0
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
		}
	}
}
Beispiel #2
0
// 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))
	}
}
Beispiel #3
0
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
}
Beispiel #4
0
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)
	}
}
Beispiel #5
0
// 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)
	}
}
Beispiel #6
0
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)
}
Beispiel #7
0
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
}
Beispiel #8
0
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
}
Beispiel #9
0
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
	}
}
Beispiel #10
0
// 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()
}
Beispiel #11
0
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()))
			}
		}
	}
}