func (d *directProcess) watch(cmd *exec.Cmd, exitSubscription *subreaper.Subscription) { defer subreaper.Unsubscribe(exitSubscription) defer d.delete() f, err := os.OpenFile(path.Join(d.root, ExitFile), syscall.O_WRONLY, 0) if err == nil { defer f.Close() } exitCode := 0 if err = cmd.Wait(); err != nil { if exitError, ok := err.(exec.ExitCodeError); ok { exitCode = exitError.Code } } if exitCode == 0 { pid, err := d.getPidFromFile() if err != nil { return } exitSubscription.SetPid(pid) exitCode = exitSubscription.Wait() } writeInt(path.Join(d.root, ExitStatusFile), exitCode) }
func (p *process) startCmd(cmd *exec.Cmd) error { if err := cmd.Start(); err != nil { if exErr, ok := err.(*exec.Error); ok { if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist { return fmt.Errorf("%s not installed on system", p.container.shim) } } return err } if err := p.waitForStart(cmd); err != nil { return err } return nil }
// cmdStream executes a command, and returns its stdout as a stream. // If the command fails to run or doesn't complete successfully, an error // will be returned, including anything written on stderr. func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, <-chan struct{}, error) { chdone := make(chan struct{}) cmd.Stdin = input pipeR, pipeW := io.Pipe() cmd.Stdout = pipeW var errBuf bytes.Buffer cmd.Stderr = &errBuf // Run the command and return the pipe if err := cmd.Start(); err != nil { return nil, nil, err } // Copy stdout to the returned pipe go func() { if err := cmd.Wait(); err != nil { pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String())) } else { pipeW.Close() } close(chdone) }() return pipeR, chdone, nil }
func (p *process) waitForStart(cmd *exec.Cmd) error { wc := make(chan error, 1) go func() { for { if _, err := p.getPidFromFile(); err != nil { if os.IsNotExist(err) || err == errInvalidPidInt { alive, err := isAlive(cmd) if err != nil { wc <- err return } if !alive { // runc could have failed to run the container so lets get the error // out of the logs or the shim could have encountered an error messages, err := readLogMessages(filepath.Join(p.root, "shim-log.json")) if err != nil && !os.IsNotExist(err) { wc <- err return } for _, m := range messages { if m.Level == "error" { wc <- fmt.Errorf("shim error: %v", m.Msg) return } } // no errors reported back from shim, check for runc/runtime errors messages, err = readLogMessages(filepath.Join(p.root, "log.json")) if err != nil { if os.IsNotExist(err) { err = ErrContainerNotStarted } wc <- err return } for _, m := range messages { if m.Level == "error" { wc <- fmt.Errorf("oci runtime error: %v", m.Msg) return } } wc <- ErrContainerNotStarted return } time.Sleep(15 * time.Millisecond) continue } wc <- err return } // the pid file was read successfully wc <- nil return } }() select { case err := <-wc: if err != nil { return err } return nil case <-time.After(p.container.timeout): cmd.Process.Kill() cmd.Wait() return ErrContainerStartTimeout } }