Beispiel #1
0
// checkForDeath tries to clean up zombies and then checks if the
// process group is empty.
//
// It returns "true" if the answer is yes and there are no grace pings left
//
func (n *nelly) checkForDeath() bool {

	// Check if there are any zombies to eat. Process.Wait() doesn't
	// support the POSIX WNOHANG for portability reasons, so let's use
	// the syscall.Wait4() which is POSIX-only.
	var w syscall.WaitStatus
	rusage := syscall.Rusage{}
	zpid, err := syscall.Wait4(-1, &w, syscall.WNOHANG, &rusage)
	if err != nil {
		n.Error("Error in Wait4: %s", err.Error())
	}
	if zpid > 0 {
		n.Error("Ate a tasty zombie (pid was %d, status was %d)", zpid, w.ExitStatus())
	}

	if n.processGroupIsEmpty() {
		n.startGracePings--
		if n.startGracePings <= 0 {
			n.Error("Process group [%d] empty - exiting and hoping init sorts it all out", n.pgid)
			return true
		} else {
			n.Error("Process group [%d] empty - grace pings left [%d]", n.pgid, n.startGracePings)
		}
	} else {
		// We've had a good ping, no more Mr Nice Guy
		n.startGracePings = 0
	}
	return false
}
Beispiel #2
0
func ExecBash(command string, args []string) (int, string, error) {
	cmd := exec.Command(command, args...)
	var waitStatus syscall.WaitStatus

	//Stdout buffer
	cmdOutput := &bytes.Buffer{}

	//Attach buffer to command stdout
	cmd.Stdout = cmdOutput

	//Execute command
	err := cmd.Run()

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Command:%s execute error\n", command)
		}
	}()

	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			return waitStatus.ExitStatus(), "", err
		} else {
			fmt.Println("something wrong")
		}
	}
	waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
	return waitStatus.ExitStatus(), cmdOutput.String(), nil

}
Beispiel #3
0
func (m *Module) IsRunning() bool {
	pid := 0
	if m.Name == "internal:shared" {
		pid = m.SyncProcess.Pid
	} else {
		pid = m.MainProcess.Pid
	}

	var waitstatus syscall.WaitStatus
	wpid, err := syscall.Wait4(pid, &waitstatus, syscall.WNOHANG|syscall.WUNTRACED, nil)
	if err != nil {
		// When would this happen?
		log.Println("Unable to get process wait status:", err)
		// Assume it is not running
		return false
	}

	// If status is not available, the pid is 0.
	if wpid == 0 {
		return true
	}
	if waitstatus.Exited() {
		delete(modules, m.Name)
		return false
	}
	return true
}
Beispiel #4
0
func babySit(process *os.Process) int {
	// Forward all signals to the app
	sigchan := make(chan os.Signal, 1)
	sigutil.CatchAll(sigchan)
	go func() {
		for sig := range sigchan {
			if sig == syscall.SIGCHLD {
				continue
			}
			process.Signal(sig)
		}
	}()

	// Wait for the app to exit.  Also, as pid 1 it's our job to reap all
	// orphaned zombies.
	var wstatus syscall.WaitStatus
	for {
		pid, err := syscall.Wait4(-1, &wstatus, 0, nil)
		if err == nil && pid == process.Pid {
			break
		}
	}

	return wstatus.ExitStatus()
}
Beispiel #5
0
func (t *tracerImpl) Run() (err error) {

	if t.cmd.SysProcAttr == nil {
		t.cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true}
	} else {
		t.cmd.SysProcAttr.Ptrace = true
	}

	runtime.LockOSThread()

	if err = t.cmd.Start(); err != nil {
		return
	}

	var waitStatus syscall.WaitStatus

	if _, err = syscall.Wait4(t.cmd.Process.Pid, &waitStatus, 0, nil); err != nil {
		return
	}

	if waitStatus.Exited() {
		return
	}

	// Set options to detect our syscalls
	if err = syscall.PtraceSetOptions(t.cmd.Process.Pid, syscall.PTRACE_O_TRACESYSGOOD); err != nil {
		return
	}

	var regsEntry, regsExit syscall.PtraceRegs
	// Get first syscall
	if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, &regsEntry); err != nil {
		return
	}

	var exited bool
	for {
		if exited, err = wait_for_syscall(t.cmd.Process.Pid); exited || err != nil {
			return
		}

		// Get syscall info
		if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, &regsEntry); err != nil {
			return
		}

		// Enter syscall
		t.callback(regsEntry, false)

		if exited, err = wait_for_syscall(t.cmd.Process.Pid); exited || err != nil {
			return
		}

		// Get syscall returned value
		if err = syscall.PtraceGetRegs(t.cmd.Process.Pid, &regsExit); err != nil {
			return
		}
		t.callback(regsExit, true)
	}
}
Beispiel #6
0
func babySit(process *os.Process) int {
	log := logger.New("fn", "babySit")

	// Forward all signals to the app
	sigchan := make(chan os.Signal, 1)
	sigutil.CatchAll(sigchan)
	go func() {
		for sig := range sigchan {
			log.Info("received signal", "type", sig)
			if sig == syscall.SIGCHLD {
				continue
			}
			log.Info("forwarding signal to command", "type", sig)
			process.Signal(sig)
		}
	}()

	// Wait for the app to exit.  Also, as pid 1 it's our job to reap all
	// orphaned zombies.
	var wstatus syscall.WaitStatus
	for {
		pid, err := syscall.Wait4(-1, &wstatus, 0, nil)
		if err == nil && pid == process.Pid {
			break
		}
	}

	if wstatus.Signaled() {
		log.Info("command exited due to signal")
		return 0
	}
	return wstatus.ExitStatus()
}
Beispiel #7
0
func ConvertOfficeDocToPdf2(file string) {
	args := []string{"-f", "pdf",
		"-eSelectPdfVersion=1",
		"-eReduceImageResolution=true",
		"-eMaxImageResolution=300",
		"-p",
		"8200",
		"-o",
		"~/foo1.pdf",
		"~/foo.pptx",
	}
	cmd := exec.Command("unoconv", args...)
	var waitStatus syscall.WaitStatus
	if err := cmd.Run(); err != nil {
		//fmt.Printf("Error:", err)
		// Did the command fail because of an unsuccessful exit code
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			fmt.Printf("Failed: %d", waitStatus.ExitStatus())
		}
	} else {
		// Command was successful
		waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
		fmt.Printf("Success: %d", waitStatus.ExitStatus())
	}
}
Beispiel #8
0
func Shell(f string, v ...interface{}) (retCode int, stdout, stderr string) {
	var so, se bytes.Buffer
	command := exec.Command("bash", "-c", fmt.Sprintf(f, v...))
	command.Stdout = &so
	command.Stderr = &se

	var waitStatus syscall.WaitStatus
	if err := command.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			retCode = waitStatus.ExitStatus()
		} else {
			// looks like a system error, for example, IO error
			panic(err)
		}
	} else {
		waitStatus = command.ProcessState.Sys().(syscall.WaitStatus)
		retCode = waitStatus.ExitStatus()
	}

	stdout = string(so.Bytes())
	stderr = string(se.Bytes())

	return
}
func (p *ProcessReaper) reap() {
	for {
		p.log.Debug("reap")
		var status syscall.WaitStatus
		var rusage syscall.Rusage
		wpid, err := p.wait4(-1, &status, syscall.WNOHANG, &rusage)

		if wpid == 0 || (wpid == -1 && err.Error() == "no child processes") {
			break
		}

		if err != nil {
			p.log.Error("reaper-wait-error", err, lager.Data{"wpid": wpid})
			break
		}

		p.log.Info("reaped", lager.Data{"pid": wpid, "status": status, "rusage": rusage})

		if ch, ok := p.waitChan(wpid); p.monitoredPids[wpid] && ok {
			ch <- status.ExitStatus()
			p.unmonitorPid(wpid)

			p.log.Info("wait-once-sent-exit-status", lager.Data{"pid": wpid, "status": status, "rusage": rusage})
		} else {
			p.log.Info("wait-once-not-found", lager.Data{"pid": wpid, "status": status, "rusage": rusage})
		}
	}
}
Beispiel #10
0
// Called on running checks, to determine if they have finished
// running.
//
// If the Check has not finished executing, returns false.
//
// If the Check has been running for longer than its Timeout,
// a SIGTERM (and failing that a SIGKILL) is issued to forcibly
// terminate the rogue Check process. In either case, this returns
// as if the check has not yet finished, and Reap() will need to be
// called again to fully reap the Check
//
// If the Check has finished execution (on its own, or via forced
// termination), it will return true.
//
// Once complete, some additional meta-stats for the check execution
// are appended to the check output, to be submit up to bolo
func (self *Check) Reap() bool {
	pid := self.process.Process.Pid

	var ws syscall.WaitStatus
	status, err := syscall.Wait4(pid, &ws, syscall.WNOHANG, nil)
	if err != nil {
		log.Error("Error waiting on check %s[%d]: %s", self.Name, pid, err.Error())
		return false
	}
	if status == 0 {
		// self to see if we need to sigkill due to failed sigterm
		if time.Now().After(self.started_at.Add(time.Duration(self.Timeout+2) * time.Second)) {
			log.Warn("Check %s[%d] has been running too long, sending SIGKILL", self.Name, pid)
			if err := syscall.Kill(pid, syscall.SIGKILL); err != nil {
				log.Error("Error sending SIGKILL to check %s[%d]: %s", self.Name, pid, err.Error())
			}
			self.sig_kill = true
		}
		// self to see if we need to sigterm due to self timeout expiry
		if !self.sig_kill && time.Now().After(self.started_at.Add(time.Duration(self.Timeout)*time.Second)) {
			log.Warn("Check %s[%d] has been running too long, sending SIGTERM", self.Name, pid)
			if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
				log.Error("Error sending SIGTERM to check %s[%d]: %s", self.Name, pid, err.Error())
			}
			self.sig_term = true
		}
		return false
	}

	self.ended_at = time.Now()
	self.running = false
	self.duration = time.Since(self.started_at)
	self.latency = self.started_at.Sub(self.next_run)
	self.output = string(self.stdout.Bytes())
	self.err_msg = string(self.stderr.Bytes())

	if ws.Exited() {
		self.rc = ws.ExitStatus()
	} else {
		log.Debug("Check %s[%d] exited abnormally (signaled/stopped). Setting rc to UNKNOWN", self.Name, pid)
		self.rc = UNKNOWN
	}
	if self.rc > UNKNOWN {
		log.Debug("Check %s[%d] returned with an invalid exit code. Setting rc to UNKOWN", self.Name, pid)
		self.rc = UNKNOWN
	}

	self.reschedule()

	if self.ended_at.After(self.next_run) {
		timeout_triggered := "not reached"
		if self.sig_term || self.sig_kill {
			timeout_triggered = "reached"
		}
		log.Warn("Check %s[%d] took %0.3f seconds to run, at interval %d (timeout of %d was %s)",
			self.Name, pid, self.duration.Seconds(), self.Every, self.Timeout, timeout_triggered)
	}
	return true
}
Beispiel #11
0
func GetCommandExitCode(err error) int {
	var waitStatus syscall.WaitStatus
	if exitError, ok := err.(*exec.ExitError); ok {
		waitStatus = exitError.Sys().(syscall.WaitStatus)
		return waitStatus.ExitStatus()
	}
	return 0
}
Beispiel #12
0
func (proc *Proc) Start() (safeExit bool, err error) {
	log.Printf("supervisor running command: %s\n", proc.command)
	commandParts := strings.Fields(proc.command)
	commandString := commandParts[0]
	commandArgs := commandParts[1:len(commandParts)]

	proc.cmd = exec.Command(commandString, commandArgs...)

	proc.cmd.Stdout = os.Stdout
	proc.cmd.Stderr = os.Stderr

	proc.AddSignalHandlers()
	cmdErr := proc.cmd.Start()
	if cmdErr != nil {
		log.Fatal(cmdErr)
	}

	done := make(chan error, 1)
	go func() {
		done <- proc.cmd.Wait()
	}()

	//process waits here
	exitCode := <-done
	if exitCode != nil {
		// Type Assertion of exitCode with exec.ExitError struct
		var waitStatus syscall.WaitStatus
		exitError, ok := exitCode.(*exec.ExitError)
		if ok {
			// exitError.Sys() returns system specific exit info
			// Type Assertion of exitError.Sys() to sysCall.Waitstatus for Unix
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			exitStatus := waitStatus.ExitStatus()
			if exitStatus == 130 {
				log.Printf("Process killed manually, aborting restart \n")
				return true, nil
			} else {
				proc.exitCode = exitStatus
				proc.procError = fmt.Sprintf("%v", exitCode)
				log.Printf("%v", proc.procError)
				if proc.restartCount < proc.maxRestartCount {
					log.Printf("Restarting app, Restart count %d, Max restart count %d", proc.restartCount, proc.maxRestartCount)
					proc.restartCount += 1
					proc.Start()
				} else {
					log.Printf("Max restart count (%d) reached, exiting", proc.maxRestartCount)
					log.Printf("--------- Command exited ----------- \n")
				}
			}
		}
	} else {
		// command exited successfully with return code = 0
		proc.exitCode = 0
		proc.restartCount += 1
		proc.Start()
	}
	return true, nil
}
Beispiel #13
0
// ExitCode returns the exit code of the command denoted by this struct
func (pr *ProcessResult) ExitCode() int {
	var waitStatus syscall.WaitStatus
	if exitError, ok := pr.ProcessError.(*exec.ExitError); ok {
		waitStatus = exitError.Sys().(syscall.WaitStatus)
	} else {
		waitStatus = pr.ProcessState.Sys().(syscall.WaitStatus)
	}
	return waitStatus.ExitStatus()
}
Beispiel #14
0
func (d *daemonState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
	d.Debug("Child process pid=%d exited from daemon with status %d", pid, wstatus.ExitStatus())
	for _, sbox := range d.sandboxes {
		if sbox.init.Process.Pid == pid {
			sbox.remove(d.log)
			return
		}
	}
	d.Notice("No sandbox found with oz-init pid = %d", pid)
}
Beispiel #15
0
func run() int {
	flag.Parse()

	runtime := flag.Args()[1] // e.g. runc
	dir := flag.Args()[2]     // bundlePath for run, processPath for exec
	containerId := flag.Args()[3]

	signals := make(chan os.Signal, 100)
	signal.Notify(signals, syscall.SIGCHLD)

	fd3 := os.NewFile(3, "/proc/self/fd/3")
	logFile := fmt.Sprintf("/proc/%d/fd/4", os.Getpid())
	logFD := os.NewFile(4, "/proc/self/fd/4")
	syncPipe := os.NewFile(5, "/proc/self/fd/5")
	pidFilePath := filepath.Join(dir, "pidfile")

	stdin, stdout, stderr, winsz := openPipes(dir)

	syncPipe.Write([]byte{0})

	var runcStartCmd *exec.Cmd
	if *tty {
		ttySlave := setupTty(stdin, stdout, pidFilePath, winsz, garden.WindowSize{Rows: *rows, Columns: *cols})
		runcStartCmd = exec.Command(runtime, "-debug", "-log", logFile, "exec", "-d", "-tty", "-console", ttySlave.Name(), "-p", fmt.Sprintf("/proc/%d/fd/0", os.Getpid()), "-pid-file", pidFilePath, containerId)
	} else {
		runcStartCmd = exec.Command(runtime, "-debug", "-log", logFile, "exec", "-p", fmt.Sprintf("/proc/%d/fd/0", os.Getpid()), "-d", "-pid-file", pidFilePath, containerId)
		runcStartCmd.Stdin = stdin
		runcStartCmd.Stdout = stdout
		runcStartCmd.Stderr = stderr
	}

	// we need to be the subreaper so we can wait on the detached container process
	system.SetSubreaper(os.Getpid())

	if err := runcStartCmd.Start(); err != nil {
		fd3.Write([]byte{2})
		return 2
	}

	var status syscall.WaitStatus
	var rusage syscall.Rusage
	_, err := syscall.Wait4(runcStartCmd.Process.Pid, &status, 0, &rusage)
	check(err)    // Start succeeded but Wait4 failed, this can only be a programmer error
	logFD.Close() // No more logs from runc so close fd

	fd3.Write([]byte{byte(status.ExitStatus())})
	if status.ExitStatus() != 0 {
		return 3 // nothing to wait for, container didn't launch
	}

	containerPid, err := parsePid(pidFilePath)
	check(err)

	return waitForContainerToExit(dir, containerPid, signals)
}
Beispiel #16
0
/* output diff */
func checkStringsEqual(expected, actual string) (ok bool, diff string, err error) {
	if expected == actual {
		ok = true
		return
	}

	var exp *os.File
	exp, err = ioutil.TempFile("", "expected")
	if err != nil {
		return
	}
	defer exp.Close()
	defer os.Remove(exp.Name())
	_, err = exp.Write([]byte(expected))
	if err != nil {
		return
	}
	exp.Sync()

	var act *os.File
	act, err = ioutil.TempFile("", "actual")
	if err != nil {
		return
	}
	defer act.Close()
	defer os.Remove(act.Name())
	_, err = act.Write([]byte(actual))
	if err != nil {
		return
	}
	act.Sync()

	// diff's exit status is 1 if the files differ, and Go returns an error
	// when the exit status is non-zero
	cmd := exec.Command("diff", "-u", exp.Name(), act.Name())
	var cmdOutput []byte
	cmdOutput, err = cmd.Output()
	if err != nil {
		var typeOk bool
		var exitErr *exec.ExitError
		exitErr, typeOk = err.(*exec.ExitError)
		if !typeOk {
			return
		}

		var status syscall.WaitStatus
		status, typeOk = exitErr.Sys().(syscall.WaitStatus)
		if !typeOk || status.ExitStatus() > 1 {
			return
		}
		err = nil
	}
	diff = string(cmdOutput)
	return
}
Beispiel #17
0
func execFgCmd(cmd []string, sigStateChanged chan string) {
	cmdStr := strings.Join(cmd, " ")

	// TODO: Extract start process into common function.
	argv0, err := exec.LookPath(cmd[0])
	if err != nil {
		if cmd[0] != "" {
			fmt.Printf("Unknown command: %s\n", cmd[0])
		}
		// Don't execute new process with empty return. Will cause panic.
		sigPrompt <- struct{}{}
		return
	}
	var procAttr os.ProcAttr
	procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}

	p, err := os.StartProcess(argv0, cmd, &procAttr)
	if err != nil {
		fmt.Printf("Start process %s, %s failed: %v", err, argv0, cmd)
	}

	for {
		sigChild := make(chan os.Signal)
		defer close(sigChild)
		// SIGCONT not receivable: https://github.com/golang/go/issues/8953
		// This causes some bugs. Eg. CONT signal not captured by handler means subsequent KILL or STOP signals will be ignored by this handler.
		signal.Notify(sigChild, syscall.SIGTSTP, syscall.SIGINT, syscall.SIGCONT, syscall.SIGKILL)
		defer signal.Stop(sigChild)

		var ws syscall.WaitStatus
		// Ignoring error. May return "no child processes" error. Eg. Sending Ctrl-c on `cat` command.
		wpid, _ := syscall.Wait4(p.Pid, &ws, syscall.WUNTRACED, nil)

		if ws.Exited() {
			break
		}
		if ws.Stopped() {
			jobHandler(wpid, runningState, cmdStr)
			jobHandler(wpid, suspendedState, cmdStr)
			// Return prompt when fg has become bg
			sigPrompt <- struct{}{}
		}
		//if ws.Continued() {
		//	state = contState
		//}
		if ws == 9 {
			jobHandler(wpid, killedState, cmdStr)
			break
		}
	}

	p.Wait()
	sigPrompt <- struct{}{}
}
Beispiel #18
0
func ParseFile(file string) (*Program, error) {
	var status syscall.WaitStatus
	var exitCode int
	var err error

	acornPath := GetAcornPath()

	cmd := exec.Command(acornPath, "--ecma6", "--module", file)

	stdoutBuffer := &bytes.Buffer{}
	stderrBuffer := &bytes.Buffer{}

	cmd.Stdout = stdoutBuffer
	cmd.Stderr = stderrBuffer

	err = cmd.Run()
	if err != nil {
		exitError, _ := err.(*exec.ExitError)
		status = exitError.Sys().(syscall.WaitStatus)
		exitCode = status.ExitStatus()
	} else {
		exitCode = -1
	}

	stdoutBytes, err := ioutil.ReadAll(stdoutBuffer)
	if err != nil {
		log.Fatal(err)
	}

	stderrBytes, err := ioutil.ReadAll(stderrBuffer)
	if err != nil {
		log.Fatal(err)
	}

	if exitCode > -1 {
		if len(stdoutBytes) > 0 {
			fmt.Println(string(stdoutBytes))
		}
		if len(stderrBytes) > 0 {
			fmt.Println(string(stderrBytes))
		}

		return nil, fmt.Errorf("Exited with code: %d; %s", exitCode, string(stderrBytes))
	}

	json, err := simplejson.NewJson(stdoutBytes)
	if err != nil {
		return nil, err
	}

	return ParseProgram(json)
}
Beispiel #19
0
func execBgCmd(cmd []string, sigStateChanged chan string) {
	cmdStr := strings.Join(cmd, " ")

	argv0, err := exec.LookPath(cmd[0])
	if err != nil {
		if cmd[0] != "" {
			fmt.Printf("Unknown command: %s\n", cmd[0])
		}
		sigPrompt <- struct{}{}
		return
	}
	var procAttr os.ProcAttr
	procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}

	p, err := os.StartProcess(argv0, cmd, &procAttr)
	if err != nil {
		fmt.Printf("Start process %s, %s failed: %v", err, argv0, cmd)
	}
	jobHandler(p.Pid, runningState, cmdStr)
	sigPrompt <- struct{}{}

	//FIXME: Bg processes should not receive keyboard signals sent to fg process.

	for {
		sigChild := make(chan os.Signal)
		defer close(sigChild)
		signal.Notify(sigChild, syscall.SIGCHLD)
		defer signal.Stop(sigChild)

		var ws syscall.WaitStatus
		wpid, _ := syscall.Wait4(p.Pid, &ws, syscall.WUNTRACED, nil)

		if ws.Exited() {
			jobHandler(wpid, doneState, cmdStr)
			break
		}
		if ws.Stopped() {
			jobHandler(wpid, suspendedState, cmdStr)
			sigPrompt <- struct{}{}
		}
		//if ws.Continued() {
		//	state = contState
		//}
		if ws == 9 {
			jobHandler(wpid, killedState, cmdStr)
			break
		}
	}

	p.Wait()
	sigPrompt <- struct{}{}
}
Beispiel #20
0
func waitPid(pid int) {
	for {
		var ws syscall.WaitStatus
		_, err := syscall.Wait4(pid, &ws, 0, nil)

		if err != nil {
			panic(err)
		}

		if ws.Exited() {
			break
		}
	}
}
Beispiel #21
0
func waitSyscall(proc *os.Process) bool {
	for {
		syscall.PtraceSyscall(proc.Pid, 0)

		var status syscall.WaitStatus
		syscall.Wait4(proc.Pid, &status, 0, nil)
		if status.Stopped() {
			return false
		}
		if status.Exited() {
			return true
		}
	}
}
Beispiel #22
0
func Wait(pid int) (int, error) {
	var wstat syscall.WaitStatus
	_, err := syscall.Wait4(pid, &wstat, 0, nil)
	if err != nil {
		if err.Error() != "no child processes" {
			log.Printf("[ERROR] [process] [%d] Wait >>> %s\n", pid, err)
			return -1, err
		}
		log.Printf("[DEBUG] [process] [%d] Wait >>> %s\n", pid, err)
		return -1, nil
	}

	status := wstat.ExitStatus()
	return status, nil
}
Beispiel #23
0
func waitStateUpdate(pid int, update chan<- *StateUpdate) {
	for {
		var ws syscall.WaitStatus
		_, err := syscall.Wait4(pid, &ws, 0, nil)

		if err != nil {
			if err != syscall.ECHILD {
				update <- &StateUpdate{Msg: err.Error()}
			}
			break
		}
		update <- &StateUpdate{
			Terminated: ws.Exited(), Msg: fmt.Sprintf("%v", ws)}
	}
	close(update)
}
Beispiel #24
0
// waitStateUpdate wait(2)s for pid, and feeds the WaitStatus's into a
// *StateUpdate channel after proper conversion.
func waitStateUpdate(pid int, update chan<- *stateUpdate) {
	for {
		var ws syscall.WaitStatus
		_, err := syscall.Wait4(pid, &ws, 0, nil)

		if err != nil {
			update <- newExitedStateUpdate(newFailure(err.Error()))
			break
		}
		update <- waitStatusToStateUpdate(ws)
		if ws.Exited() {
			break
		}
	}
	close(update)
}
Beispiel #25
0
Datei: init.go Projekt: tdr130/oz
func (st *initState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
	st.log.Debug("Child process pid=%d exited from init with status %d", pid, wstatus.ExitStatus())
	track := st.children[pid].track
	if len(st.profile.Watchdog) > 0 {
		if track == true {
			track = false
		} else {
			track = !st.getProcessExists(st.profile.Watchdog)
		}
	}
	st.removeChildProcess(pid)
	if track == true && st.profile.AutoShutdown == oz.PROFILE_SHUTDOWN_YES {
		st.log.Info("Shutting down sandbox after child exit.")
		st.shutdown()
	}
}
Beispiel #26
0
func (p *process) Wait() (uint32, error) {
	if p.status != execution.Stopped {
		var wstatus syscall.WaitStatus
		_, err := syscall.Wait4(p.pid, &wstatus, 0, nil)
		if err != nil {
			// This process doesn't belong to us
			p.exitCode = execution.UnknownStatusCode
			return p.exitCode, nil
		}
		// TODO: implement kill-all if we are the init pid?
		p.status = execution.Stopped
		p.exitCode = uint32(wstatus.ExitStatus())
	}
	return p.exitCode, nil

}
Beispiel #27
0
func (t *Task) Tracer() error {
	runtime.LockOSThread()

	if err := syscall.PtraceAttach(t.pid); err != nil {
		return err
	}
	defer func() {
		// syscall.PtraceCont(t.pid, 0)
		syscall.PtraceDetach(t.pid)
	}()

	regsout := new(syscall.PtraceRegs)
	status := new(syscall.WaitStatus)
	var timer *time.Timer
	refresh := func() { t.RefreshFiles(); timer.Stop(); timer = nil }
	for {
		if _, err := syscall.Wait4(t.pid, status, 0, nil); err != nil {
			log.Println("wait failed", err)
			return err
		}
		if status.Exited() {
			log.Println("exited")
			return nil
		}

		if err := syscall.PtraceGetRegs(t.pid, regsout); err != nil {
			log.Println("getregs failed", err)
			return err
		}

		// linux_amd64
		if regsout.Orig_rax == syscall.SYS_OPEN {
			if timer != nil {
				if timer.Stop() == false {
					log.Println("cannot stop the timer")
				}
			}
			timer = time.AfterFunc(1e9, refresh) // Wait until open()s "settle".
		}

		if err := PtraceSyscall(t.pid); err != nil {
			log.Println("PtraceSyscall failed", err)
			return err
		}
	}
	panic("can't reach")
}
Beispiel #28
0
// if we are on minikube or minishift lets try to create the
// hostPath folders with relaxed persmissions
func configureHostPathVolume(c *k8sclient.Client, ns string, hostPath string, sshCommand string) error {
	cli := sshCommand

	if len(cli) == 0 {
		context, isMini, _ := util.GetMiniType()
		if isMini {
			cli = context
		}
	}
	if len(cli) == 0 {
		// lets default to using vagrant if we have a Vagrantfile
		if _, err := os.Stat("Vagrantfile"); err == nil {
			cli = "vagrant"
		}
	}
	if len(cli) == 0 {
		return nil
	}

	shellCommands := []string{
		fmt.Sprintf("sudo mkdir -p %s", hostPath),
		fmt.Sprintf("sudo chmod 777 %s", hostPath),
		fmt.Sprintf("echo hostPath is setup correctly at: %s", hostPath),
	}
	util.Infof("About to modify host paths on the VM via the command: %s\n", cli)

	for _, shellCmd := range shellCommands {
		args := []string{"ssh", fmt.Sprintf("/bin/sh -c '%s'", shellCmd)}
		cmd := exec.Command(cli, args...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		var waitStatus syscall.WaitStatus
		if err := cmd.Run(); err != nil {
			printErr(err)
			if exitError, ok := err.(*exec.ExitError); ok {
				waitStatus = exitError.Sys().(syscall.WaitStatus)
				printStatus(waitStatus.ExitStatus())
			}
			return err
		} else {
			waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
			printStatus(waitStatus.ExitStatus())
		}
	}
	return nil
}
Beispiel #29
0
func (c *CloneParams) CloneFrozen() (int, error) {
	pid := callClone(c)
	// TODO: clone errors?
	c.CommWriter.Close()
	c.stdhandles.Close()
	c.comm = make(chan CommStatus)
	go commReader(c.CommReader, c.comm)

	var status syscall.WaitStatus
	for {
		wpid, err := syscall.Wait4(pid, &status, 0, nil) // TODO: rusage
		if err != nil {
			return -1, os.NewSyscallError("Wait4", err)
		}
		if wpid == pid {
			break
		}
	}
	if status.Stopped() && status.StopSignal() == syscall.SIGTRAP {
		return pid, nil
	}
	if status.Exited() {
		co, ok := <-c.comm
		if ok {
			return -1, childError(co)
		}
		return -1, fmt.Errorf("DAFUQ")
	}
	err := syscall.Kill(pid, syscall.SIGKILL)
	if err != nil {
		return -1, os.NewSyscallError("Kill", err)
	}
	return -1, fmt.Errorf("traps, signals, dafuq is this")
}
Beispiel #30
0
// StartProcess kicks off the event loop and forever waits for signals from
// the traced process. This is currently done in a super-silly fashion and will
// hopefully benefit from Go channels/goroutines in the future.
func (p *Process) StartProcess() (ret int) {
	var status syscall.WaitStatus

L:
	for {
		_, err := syscall.Wait4( /*p.Pid*/ -1, &status, 0, nil)
		p.isRunning = false

		switch {
		// status == 0  means terminated??
		case status.Exited() || status == 0 || err != nil:
			ret = status.ExitStatus()
			break L
		case status.Stopped():
			if bp, hit := p.InBreakpoint(); hit {
				p.handleBreakpoint(bp)
			}

		//case status.Continued():
		//case status.CoreDump():
		//case status.Signaled():
		//case status.ExitStatus():
		//case status.StopSignal():
		//case status.TrapCause():
		default:
			// fmt.Printf("Got status: %v\n", status)
		}

		p.Continue()

	}
	return
}