package libcontainer import ( "errors" "io" "math" "os" "github.com/opencontainers/runc/libcontainer/configs" ) var errInvalidProcess = errors.New("invalid process") type processOperations interface { wait() (*os.ProcessState, error) signal(sig os.Signal) error pid() int } // Process defines the configuration and IO for a process inside a container. // // Note that some Process properties are also present in container configuration // ([configs.Config]). In all such cases, Process properties take precedence // over container configuration ones. type Process struct { // The command to be run followed by any arguments. Args []string // Env specifies the environment variables for the process. Env []string // UID and GID of the executing process running inside the container // local to the container's user and group configuration. UID, GID int // AdditionalGroups specifies the gids that should be added to supplementary groups // in addition to those that the user belongs to. AdditionalGroups []int // Cwd will change the process's current working directory inside the container's rootfs. Cwd string // Stdin is a reader which provides the standard input stream. Stdin io.Reader // Stdout is a writer which receives the standard output stream. Stdout io.Writer // Stderr is a writer which receives the standard error stream. Stderr io.Writer // ExtraFiles specifies additional open files to be inherited by the process. ExtraFiles []*os.File // Open handles to cloned binaries -- see dmz.CloneSelfExe for more details. clonedExes []*os.File // Initial size for the console. ConsoleWidth uint16 ConsoleHeight uint16 // Capabilities specify the capabilities to keep when executing the process. // All capabilities not specified will be dropped from the processes capability mask. // // If not nil, takes precedence over container's [configs.Config.Capabilities]. Capabilities *configs.Capabilities // AppArmorProfile specifies the profile to apply to the process and is // changed at the time the process is executed. // // If not empty, takes precedence over container's [configs.Config.AppArmorProfile]. AppArmorProfile string // Label specifies the label to apply to the process. It is commonly used by selinux. // // If not empty, takes precedence over container's [configs.Config.ProcessLabel]. Label string // NoNewPrivileges controls whether processes can gain additional privileges. // // If not nil, takes precedence over container's [configs.Config.NoNewPrivileges]. NoNewPrivileges *bool // Rlimits specifies the resource limits, such as max open files, to set for the process. // If unset, the process will inherit rlimits from the parent process. // // If not empty, takes precedence over container's [configs.Config.Rlimit]. Rlimits []configs.Rlimit // ConsoleSocket provides the masterfd console. ConsoleSocket *os.File // PidfdSocket provides process file descriptor of it own. PidfdSocket *os.File // Init specifies whether the process is the first process in the container. Init bool ops processOperations // LogLevel is a string containing a numeric representation of the current // log level (i.e. "4", but never "info"). It is passed on to runc init as // _LIBCONTAINER_LOGLEVEL environment variable. LogLevel string // SubCgroupPaths specifies sub-cgroups to run the process in. // Map keys are controller names, map values are paths (relative to // container's top-level cgroup). // // If empty, the default top-level container's cgroup is used. // // For cgroup v2, the only key allowed is "". SubCgroupPaths map[string]string // Scheduler represents the scheduling attributes for a process. // // If not empty, takes precedence over container's [configs.Config.Scheduler]. Scheduler *configs.Scheduler // IOPriority is a process I/O priority. // // If not empty, takes precedence over container's [configs.Config.IOPriority]. IOPriority *configs.IOPriority } // Wait waits for the process to exit. // Wait releases any resources associated with the Process func (p Process) Wait() (*os.ProcessState, error) { if p.ops == nil { return nil, errInvalidProcess } return p.ops.wait() } // Pid returns the process ID func (p Process) Pid() (int, error) { // math.MinInt32 is returned here, because it's invalid value // for the kill() system call. if p.ops == nil { return math.MinInt32, errInvalidProcess } return p.ops.pid(), nil } // Signal sends a signal to the Process. func (p Process) Signal(sig os.Signal) error { if p.ops == nil { return errInvalidProcess } return p.ops.signal(sig) } // closeClonedExes cleans up any existing cloned binaries associated with the // Process. func (p *Process) closeClonedExes() { for _, exe := range p.clonedExes { _ = exe.Close() } p.clonedExes = nil } // IO holds the process's STDIO type IO struct { Stdin io.WriteCloser Stdout io.ReadCloser Stderr io.ReadCloser }