// 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 }
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 }
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 }
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() }
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, ®sEntry); 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, ®sEntry); 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, ®sExit); err != nil { return } t.callback(regsExit, true) } }
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() }
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()) } }
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}) } } }
// 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 }
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 }
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 }
// 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() }
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) }
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) }
/* 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 }
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{}{} }
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) }
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{}{} }
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 } } }
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 } } }
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 }
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) }
// 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) }
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() } }
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 }
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") }
// 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 }
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") }
// 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 }