Windows will not use containerd and its just unused code and unneed complexity to keep it all around. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
		
			
				
	
	
		
			242 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package runtime
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"io/ioutil"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"strconv"
 | 
						|
	"syscall"
 | 
						|
 | 
						|
	"github.com/docker/containerd/specs"
 | 
						|
)
 | 
						|
 | 
						|
type Process interface {
 | 
						|
	io.Closer
 | 
						|
 | 
						|
	// ID of the process.
 | 
						|
	// This is either "init" when it is the container's init process or
 | 
						|
	// it is a user provided id for the process similar to the container id
 | 
						|
	ID() string
 | 
						|
	CloseStdin() error
 | 
						|
	Resize(int, int) error
 | 
						|
	// ExitFD returns the fd the provides an event when the process exits
 | 
						|
	ExitFD() int
 | 
						|
	// ExitStatus returns the exit status of the process or an error if it
 | 
						|
	// has not exited
 | 
						|
	ExitStatus() (int, error)
 | 
						|
	// Spec returns the process spec that created the process
 | 
						|
	Spec() specs.ProcessSpec
 | 
						|
	// Signal sends the provided signal to the process
 | 
						|
	Signal(os.Signal) error
 | 
						|
	// Container returns the container that the process belongs to
 | 
						|
	Container() Container
 | 
						|
	// Stdio of the container
 | 
						|
	Stdio() Stdio
 | 
						|
	// SystemPid is the pid on the system
 | 
						|
	SystemPid() int
 | 
						|
	// State returns if the process is running or not
 | 
						|
	State() State
 | 
						|
}
 | 
						|
 | 
						|
type processConfig struct {
 | 
						|
	id          string
 | 
						|
	root        string
 | 
						|
	processSpec specs.ProcessSpec
 | 
						|
	spec        *specs.Spec
 | 
						|
	c           *container
 | 
						|
	stdio       Stdio
 | 
						|
	exec        bool
 | 
						|
	checkpoint  string
 | 
						|
}
 | 
						|
 | 
						|
func newProcess(config *processConfig) (*process, error) {
 | 
						|
	p := &process{
 | 
						|
		root:      config.root,
 | 
						|
		id:        config.id,
 | 
						|
		container: config.c,
 | 
						|
		spec:      config.processSpec,
 | 
						|
		stdio:     config.stdio,
 | 
						|
	}
 | 
						|
	uid, gid, err := getRootIDs(config.spec)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	f, err := os.Create(filepath.Join(config.root, "process.json"))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
 | 
						|
	ps := ProcessState{
 | 
						|
		ProcessSpec: config.processSpec,
 | 
						|
		Exec:        config.exec,
 | 
						|
		PlatformProcessState: PlatformProcessState{
 | 
						|
			Checkpoint: config.checkpoint,
 | 
						|
			RootUID:    uid,
 | 
						|
			RootGID:    gid,
 | 
						|
		},
 | 
						|
		Stdin:       config.stdio.Stdin,
 | 
						|
		Stdout:      config.stdio.Stdout,
 | 
						|
		Stderr:      config.stdio.Stderr,
 | 
						|
		RuntimeArgs: config.c.runtimeArgs,
 | 
						|
		NoPivotRoot: config.c.noPivotRoot,
 | 
						|
	}
 | 
						|
 | 
						|
	if err := json.NewEncoder(f).Encode(ps); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	exit, err := getExitPipe(filepath.Join(config.root, ExitFile))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	control, err := getControlPipe(filepath.Join(config.root, ControlFile))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	p.exitPipe = exit
 | 
						|
	p.controlPipe = control
 | 
						|
	return p, nil
 | 
						|
}
 | 
						|
 | 
						|
func loadProcess(root, id string, c *container, s *ProcessState) (*process, error) {
 | 
						|
	p := &process{
 | 
						|
		root:      root,
 | 
						|
		id:        id,
 | 
						|
		container: c,
 | 
						|
		spec:      s.ProcessSpec,
 | 
						|
		stdio: Stdio{
 | 
						|
			Stdin:  s.Stdin,
 | 
						|
			Stdout: s.Stdout,
 | 
						|
			Stderr: s.Stderr,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	if _, err := p.getPidFromFile(); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if _, err := p.ExitStatus(); err != nil {
 | 
						|
		if err == ErrProcessNotExited {
 | 
						|
			exit, err := getExitPipe(filepath.Join(root, ExitFile))
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			p.exitPipe = exit
 | 
						|
			return p, nil
 | 
						|
		}
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return p, nil
 | 
						|
}
 | 
						|
 | 
						|
type process struct {
 | 
						|
	root        string
 | 
						|
	id          string
 | 
						|
	pid         int
 | 
						|
	exitPipe    *os.File
 | 
						|
	controlPipe *os.File
 | 
						|
	container   *container
 | 
						|
	spec        specs.ProcessSpec
 | 
						|
	stdio       Stdio
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) ID() string {
 | 
						|
	return p.id
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) Container() Container {
 | 
						|
	return p.container
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) SystemPid() int {
 | 
						|
	return p.pid
 | 
						|
}
 | 
						|
 | 
						|
// ExitFD returns the fd of the exit pipe
 | 
						|
func (p *process) ExitFD() int {
 | 
						|
	return int(p.exitPipe.Fd())
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) CloseStdin() error {
 | 
						|
	_, err := fmt.Fprintf(p.controlPipe, "%d %d %d\n", 0, 0, 0)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) Resize(w, h int) error {
 | 
						|
	_, err := fmt.Fprintf(p.controlPipe, "%d %d %d\n", 1, w, h)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) ExitStatus() (int, error) {
 | 
						|
	data, err := ioutil.ReadFile(filepath.Join(p.root, ExitStatusFile))
 | 
						|
	if err != nil {
 | 
						|
		if os.IsNotExist(err) {
 | 
						|
			return -1, ErrProcessNotExited
 | 
						|
		}
 | 
						|
		return -1, err
 | 
						|
	}
 | 
						|
	if len(data) == 0 {
 | 
						|
		return -1, ErrProcessNotExited
 | 
						|
	}
 | 
						|
	return strconv.Atoi(string(data))
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) Spec() specs.ProcessSpec {
 | 
						|
	return p.spec
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) Stdio() Stdio {
 | 
						|
	return p.stdio
 | 
						|
}
 | 
						|
 | 
						|
// Close closes any open files and/or resouces on the process
 | 
						|
func (p *process) Close() error {
 | 
						|
	return p.exitPipe.Close()
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) State() State {
 | 
						|
	if p.pid == 0 {
 | 
						|
		return Stopped
 | 
						|
	}
 | 
						|
	err := syscall.Kill(p.pid, 0)
 | 
						|
	if err != nil && err == syscall.ESRCH {
 | 
						|
		return Stopped
 | 
						|
	}
 | 
						|
	return Running
 | 
						|
}
 | 
						|
 | 
						|
func (p *process) getPidFromFile() (int, error) {
 | 
						|
	data, err := ioutil.ReadFile(filepath.Join(p.root, "pid"))
 | 
						|
	if err != nil {
 | 
						|
		return -1, err
 | 
						|
	}
 | 
						|
	i, err := strconv.Atoi(string(data))
 | 
						|
	if err != nil {
 | 
						|
		return -1, errInvalidPidInt
 | 
						|
	}
 | 
						|
	p.pid = i
 | 
						|
	return i, nil
 | 
						|
}
 | 
						|
 | 
						|
func getExitPipe(path string) (*os.File, error) {
 | 
						|
	if err := syscall.Mkfifo(path, 0755); err != nil && !os.IsExist(err) {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// add NONBLOCK in case the other side has already closed or else
 | 
						|
	// this function would never return
 | 
						|
	return os.OpenFile(path, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
 | 
						|
}
 | 
						|
 | 
						|
func getControlPipe(path string) (*os.File, error) {
 | 
						|
	if err := syscall.Mkfifo(path, 0755); err != nil && !os.IsExist(err) {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return os.OpenFile(path, syscall.O_RDWR|syscall.O_NONBLOCK, 0)
 | 
						|
}
 | 
						|
 | 
						|
// Signal sends the provided signal to the process
 | 
						|
func (p *process) Signal(s os.Signal) error {
 | 
						|
	return syscall.Kill(p.pid, s.(syscall.Signal))
 | 
						|
}
 |