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 (d *directProcess) Start() error { cwd, err := filepath.Abs(d.root) if err != nil { return err } stdin, stdout, stderr, err := d.openIO() if err != nil { return nil } checkpoint, err := d.loadCheckpoint(d.container.bundle) if err != nil { return err } logPath := filepath.Join(cwd, "log.json") args := append([]string{ "--log", logPath, "--log-format", "json", }, d.container.runtimeArgs...) if d.exec { args = append(args, "exec", "--process", filepath.Join(cwd, "process.json"), "--console", d.consolePath, ) } else if checkpoint != nil { args = append(args, "restore", "--image-path", filepath.Join(d.container.bundle, "checkpoints", checkpoint.Name), ) add := func(flags ...string) { args = append(args, flags...) } if checkpoint.Shell { add("--shell-job") } if checkpoint.Tcp { add("--tcp-established") } if checkpoint.UnixSockets { add("--ext-unix-sk") } if d.container.noPivotRoot { add("--no-pivot") } } else { args = append(args, "start", "--bundle", d.container.bundle, "--console", d.consolePath, ) if d.container.noPivotRoot { args = append(args, "--no-pivot") } } args = append(args, "-d", "--pid-file", filepath.Join(cwd, "pid"), d.container.id, ) cmd := exec.Command(d.container.runtime, args...) cmd.Dir = d.container.bundle cmd.Stdin = stdin cmd.Stdout = stdout cmd.Stderr = stderr // set the parent death signal to SIGKILL so that if containerd dies the container // process also dies cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGKILL, } exitSubscription := subreaper.Subscribe() err = d.startCmd(cmd) if err != nil { subreaper.Unsubscribe(exitSubscription) d.delete() return err } go d.watch(cmd, exitSubscription) return nil }