2015-02-07 13:12:27 +08:00
|
|
|
// +build linux
|
|
|
|
|
|
|
|
package libcontainer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2015-03-28 01:50:32 +08:00
|
|
|
"errors"
|
2015-12-17 17:16:34 +08:00
|
|
|
"fmt"
|
2015-02-07 13:12:27 +08:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2015-03-19 11:22:21 +08:00
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
2015-02-07 13:12:27 +08:00
|
|
|
"syscall"
|
|
|
|
|
2015-06-22 10:29:59 +08:00
|
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
2015-09-11 08:57:31 +08:00
|
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
2015-06-22 10:29:59 +08:00
|
|
|
"github.com/opencontainers/runc/libcontainer/system"
|
2016-01-26 10:15:44 +08:00
|
|
|
"github.com/opencontainers/runc/libcontainer/utils"
|
2015-02-07 13:12:27 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type parentProcess interface {
|
|
|
|
// pid returns the pid for the running process.
|
|
|
|
pid() int
|
|
|
|
|
|
|
|
// start starts the process execution.
|
|
|
|
start() error
|
|
|
|
|
|
|
|
// send a SIGKILL to the process and wait for the exit.
|
|
|
|
terminate() error
|
|
|
|
|
|
|
|
// wait waits on the process returning the process state.
|
|
|
|
wait() (*os.ProcessState, error)
|
|
|
|
|
2016-09-21 20:13:32 +08:00
|
|
|
// startTime returns the process start time.
|
2015-02-07 13:12:27 +08:00
|
|
|
startTime() (string, error)
|
2015-02-07 14:33:10 +08:00
|
|
|
|
|
|
|
signal(os.Signal) error
|
2015-04-29 03:13:57 +08:00
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
externalDescriptors() []string
|
2015-04-29 04:54:03 +08:00
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
setExternalDescriptors(fds []string)
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type setnsProcess struct {
|
2015-10-17 23:14:26 +08:00
|
|
|
cmd *exec.Cmd
|
|
|
|
parentPipe *os.File
|
|
|
|
childPipe *os.File
|
|
|
|
cgroupPaths map[string]string
|
|
|
|
config *initConfig
|
|
|
|
fds []string
|
|
|
|
process *Process
|
|
|
|
bootstrapData io.Reader
|
2016-06-07 04:15:18 +08:00
|
|
|
rootDir *os.File
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *setnsProcess) startTime() (string, error) {
|
|
|
|
return system.GetProcessStartTime(p.pid())
|
|
|
|
}
|
|
|
|
|
2015-03-28 01:50:32 +08:00
|
|
|
func (p *setnsProcess) signal(sig os.Signal) error {
|
|
|
|
s, ok := sig.(syscall.Signal)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("os: unsupported signal type")
|
|
|
|
}
|
2015-09-23 10:48:36 +08:00
|
|
|
return syscall.Kill(p.pid(), s)
|
2015-02-07 14:33:10 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 13:12:27 +08:00
|
|
|
func (p *setnsProcess) start() (err error) {
|
|
|
|
defer p.parentPipe.Close()
|
2015-10-17 23:14:26 +08:00
|
|
|
err = p.cmd.Start()
|
|
|
|
p.childPipe.Close()
|
2016-06-07 04:15:18 +08:00
|
|
|
p.rootDir.Close()
|
2015-10-17 23:14:26 +08:00
|
|
|
if err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "starting setns process")
|
2015-10-17 23:14:26 +08:00
|
|
|
}
|
|
|
|
if p.bootstrapData != nil {
|
|
|
|
if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "copying bootstrap data to pipe")
|
2015-10-17 23:14:26 +08:00
|
|
|
}
|
|
|
|
}
|
2015-02-23 17:26:43 +08:00
|
|
|
if err = p.execSetns(); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "executing setns process")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
if len(p.cgroupPaths) > 0 {
|
2015-09-23 10:48:36 +08:00
|
|
|
if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
}
|
2016-03-02 02:19:07 +08:00
|
|
|
// set oom_score_adj
|
|
|
|
if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "setting oom score")
|
2016-03-02 02:19:07 +08:00
|
|
|
}
|
2016-03-25 23:03:30 +08:00
|
|
|
// set rlimits, this has to be done here because we lose permissions
|
|
|
|
// to raise the limits once we enter a user-namespace
|
|
|
|
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "setting rlimits for process")
|
2016-03-25 23:03:30 +08:00
|
|
|
}
|
2016-03-22 06:33:17 +08:00
|
|
|
if err := utils.WriteJSON(p.parentPipe, p.config); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "writing config to pipe")
|
2016-03-22 06:33:17 +08:00
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
|
2015-02-28 07:55:53 +08:00
|
|
|
if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "calling shutdown on init pipe")
|
2015-02-28 07:55:53 +08:00
|
|
|
}
|
|
|
|
// wait for the child process to fully complete and receive an error message
|
|
|
|
// if one was encoutered
|
|
|
|
var ierr *genericError
|
|
|
|
if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "decoding init error from pipe")
|
2015-02-28 07:55:53 +08:00
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
// Must be done after Shutdown so the child will exit and we can wait for it.
|
2015-02-28 07:55:53 +08:00
|
|
|
if ierr != nil {
|
2015-10-06 07:38:27 +08:00
|
|
|
p.wait()
|
2016-04-19 02:37:26 +08:00
|
|
|
return ierr
|
2015-02-28 07:55:53 +08:00
|
|
|
}
|
2015-02-07 13:12:27 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// execSetns runs the process that executes C code to perform the setns calls
|
|
|
|
// because setns support requires the C process to fork off a child and perform the setns
|
|
|
|
// before the go runtime boots, we wait on the process to die and receive the child's pid
|
|
|
|
// over the provided pipe.
|
2015-02-23 17:26:43 +08:00
|
|
|
func (p *setnsProcess) execSetns() error {
|
2015-02-07 13:12:27 +08:00
|
|
|
status, err := p.cmd.Process.Wait()
|
|
|
|
if err != nil {
|
2015-02-23 17:26:43 +08:00
|
|
|
p.cmd.Wait()
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "waiting on setns process to finish")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
if !status.Success() {
|
2015-02-23 17:26:43 +08:00
|
|
|
p.cmd.Wait()
|
|
|
|
return newSystemError(&exec.ExitError{ProcessState: status})
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
var pid *pid
|
|
|
|
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil {
|
2015-02-23 17:26:43 +08:00
|
|
|
p.cmd.Wait()
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "reading pid from init pipe")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
2015-02-23 17:26:43 +08:00
|
|
|
process, err := os.FindProcess(pid.Pid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.cmd.Process = process
|
2015-11-07 08:49:06 +08:00
|
|
|
p.process.ops = p
|
2015-02-23 17:26:43 +08:00
|
|
|
return nil
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
2016-10-12 07:22:48 +08:00
|
|
|
// avoid the process becoming a zombie.
|
2015-02-07 13:12:27 +08:00
|
|
|
func (p *setnsProcess) terminate() error {
|
2015-04-23 02:30:42 +08:00
|
|
|
if p.cmd.Process == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2015-02-23 17:26:43 +08:00
|
|
|
err := p.cmd.Process.Kill()
|
2015-02-07 13:12:27 +08:00
|
|
|
if _, werr := p.wait(); err == nil {
|
|
|
|
err = werr
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *setnsProcess) wait() (*os.ProcessState, error) {
|
2015-02-23 17:26:43 +08:00
|
|
|
err := p.cmd.Wait()
|
|
|
|
|
2015-08-12 22:37:34 +08:00
|
|
|
// Return actual ProcessState even on Wait error
|
|
|
|
return p.cmd.ProcessState, err
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *setnsProcess) pid() int {
|
2015-02-23 17:26:43 +08:00
|
|
|
return p.cmd.Process.Pid
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
func (p *setnsProcess) externalDescriptors() []string {
|
2015-04-29 04:54:03 +08:00
|
|
|
return p.fds
|
|
|
|
}
|
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
func (p *setnsProcess) setExternalDescriptors(newFds []string) {
|
2015-04-29 04:54:03 +08:00
|
|
|
p.fds = newFds
|
2015-04-29 03:13:57 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 13:12:27 +08:00
|
|
|
type initProcess struct {
|
2015-09-14 08:40:43 +08:00
|
|
|
cmd *exec.Cmd
|
|
|
|
parentPipe *os.File
|
|
|
|
childPipe *os.File
|
|
|
|
config *initConfig
|
|
|
|
manager cgroups.Manager
|
|
|
|
container *linuxContainer
|
|
|
|
fds []string
|
|
|
|
process *Process
|
|
|
|
bootstrapData io.Reader
|
|
|
|
sharePidns bool
|
2016-06-07 04:15:18 +08:00
|
|
|
rootDir *os.File
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) pid() int {
|
|
|
|
return p.cmd.Process.Pid
|
|
|
|
}
|
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
func (p *initProcess) externalDescriptors() []string {
|
2015-04-29 03:13:57 +08:00
|
|
|
return p.fds
|
|
|
|
}
|
|
|
|
|
2015-09-14 08:40:43 +08:00
|
|
|
// execSetns runs the process that executes C code to perform the setns calls
|
|
|
|
// because setns support requires the C process to fork off a child and perform the setns
|
|
|
|
// before the go runtime boots, we wait on the process to die and receive the child's pid
|
|
|
|
// over the provided pipe.
|
|
|
|
// This is called by initProcess.start function
|
|
|
|
func (p *initProcess) execSetns() error {
|
|
|
|
status, err := p.cmd.Process.Wait()
|
|
|
|
if err != nil {
|
|
|
|
p.cmd.Wait()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !status.Success() {
|
|
|
|
p.cmd.Wait()
|
|
|
|
return &exec.ExitError{ProcessState: status}
|
|
|
|
}
|
|
|
|
var pid *pid
|
|
|
|
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil {
|
|
|
|
p.cmd.Wait()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
process, err := os.FindProcess(pid.Pid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.cmd.Process = process
|
2016-05-20 08:28:58 +08:00
|
|
|
p.process.ops = p
|
2015-09-14 08:40:43 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) start() error {
|
2015-02-07 13:12:27 +08:00
|
|
|
defer p.parentPipe.Close()
|
2015-09-14 08:40:43 +08:00
|
|
|
err := p.cmd.Start()
|
2015-11-07 08:49:06 +08:00
|
|
|
p.process.ops = p
|
2015-02-07 13:12:27 +08:00
|
|
|
p.childPipe.Close()
|
2016-06-07 04:15:18 +08:00
|
|
|
p.rootDir.Close()
|
2015-02-07 13:12:27 +08:00
|
|
|
if err != nil {
|
2015-11-07 08:49:06 +08:00
|
|
|
p.process.ops = nil
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "starting init process command")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
2015-09-14 08:40:43 +08:00
|
|
|
if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := p.execSetns(); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "running exec setns process for init")
|
2015-09-14 08:40:43 +08:00
|
|
|
}
|
2015-03-19 11:22:21 +08:00
|
|
|
// Save the standard descriptor names before the container process
|
|
|
|
// can potentially move them (e.g., via dup2()). If we don't do this now,
|
|
|
|
// we won't know at checkpoint time which file descriptor to look up.
|
2015-04-29 04:54:03 +08:00
|
|
|
fds, err := getPipeFds(p.pid())
|
|
|
|
if err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", p.pid())
|
2015-03-19 11:22:21 +08:00
|
|
|
}
|
2015-04-29 23:14:54 +08:00
|
|
|
p.setExternalDescriptors(fds)
|
2015-02-07 13:12:27 +08:00
|
|
|
// Do this before syncing with child so that no children
|
|
|
|
// can escape the cgroup
|
|
|
|
if err := p.manager.Apply(p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "applying cgroup configuration for process")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
// TODO: should not be the responsibility to call here
|
|
|
|
p.manager.Destroy()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
if err := p.createNetworkInterfaces(); err != nil {
|
2016-10-11 16:38:15 +08:00
|
|
|
return newSystemErrorWithCause(err, "creating network interfaces")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
if err := p.sendConfig(); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "sending config to init process")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
var (
|
2016-02-17 18:20:06 +08:00
|
|
|
procSync syncT
|
|
|
|
sentRun bool
|
|
|
|
sentResume bool
|
|
|
|
ierr *genericError
|
2015-12-17 17:16:34 +08:00
|
|
|
)
|
|
|
|
|
2016-02-26 19:12:11 +08:00
|
|
|
dec := json.NewDecoder(p.parentPipe)
|
2015-12-17 17:16:34 +08:00
|
|
|
loop:
|
|
|
|
for {
|
2016-02-26 19:12:11 +08:00
|
|
|
if err := dec.Decode(&procSync); err != nil {
|
2015-12-17 17:16:34 +08:00
|
|
|
if err == io.EOF {
|
|
|
|
break loop
|
|
|
|
}
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "decoding sync type from init pipe")
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
2016-01-26 10:15:44 +08:00
|
|
|
switch procSync.Type {
|
2015-12-17 17:16:34 +08:00
|
|
|
case procReady:
|
|
|
|
if err := p.manager.Set(p.config.Config); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "setting cgroup config for ready process")
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
2016-03-02 02:19:07 +08:00
|
|
|
// set oom_score_adj
|
|
|
|
if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "setting oom score for ready process")
|
2016-03-02 02:19:07 +08:00
|
|
|
}
|
2016-03-25 23:03:30 +08:00
|
|
|
// set rlimits, this has to be done here because we lose permissions
|
|
|
|
// to raise the limits once we enter a user-namespace
|
|
|
|
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "setting rlimits for ready process")
|
2016-03-25 23:03:30 +08:00
|
|
|
}
|
2016-02-03 09:27:44 +08:00
|
|
|
// call prestart hooks
|
|
|
|
if !p.config.Config.Namespaces.Contains(configs.NEWNS) {
|
|
|
|
if p.config.Config.Hooks != nil {
|
|
|
|
s := configs.HookState{
|
|
|
|
Version: p.container.config.Version,
|
|
|
|
ID: p.container.id,
|
|
|
|
Pid: p.pid(),
|
|
|
|
Root: p.config.Config.Rootfs,
|
|
|
|
}
|
2016-04-19 02:37:26 +08:00
|
|
|
for i, hook := range p.config.Config.Hooks.Prestart {
|
2016-02-03 09:27:44 +08:00
|
|
|
if err := hook.Run(s); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCausef(err, "running prestart hook %d", i)
|
2016-02-03 09:27:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
// Sync with child.
|
2016-01-26 10:15:44 +08:00
|
|
|
if err := utils.WriteJSON(p.parentPipe, syncT{procRun}); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "reading syncT run type")
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
sentRun = true
|
2016-02-17 18:20:06 +08:00
|
|
|
case procHooks:
|
|
|
|
if p.config.Config.Hooks != nil {
|
|
|
|
s := configs.HookState{
|
2016-04-06 23:57:59 +08:00
|
|
|
Version: p.container.config.Version,
|
|
|
|
ID: p.container.id,
|
|
|
|
Pid: p.pid(),
|
|
|
|
Root: p.config.Config.Rootfs,
|
|
|
|
BundlePath: utils.SearchLabels(p.config.Config.Labels, "bundle"),
|
2016-02-17 18:20:06 +08:00
|
|
|
}
|
2016-04-19 02:37:26 +08:00
|
|
|
for i, hook := range p.config.Config.Hooks.Prestart {
|
2016-02-17 18:20:06 +08:00
|
|
|
if err := hook.Run(s); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCausef(err, "running prestart hook %d", i)
|
2016-02-17 18:20:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Sync with child.
|
|
|
|
if err := utils.WriteJSON(p.parentPipe, syncT{procResume}); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "reading syncT resume type")
|
2016-02-17 18:20:06 +08:00
|
|
|
}
|
|
|
|
sentResume = true
|
2015-12-17 17:16:34 +08:00
|
|
|
case procError:
|
|
|
|
// wait for the child process to fully complete and receive an error message
|
|
|
|
// if one was encoutered
|
2016-02-26 19:12:11 +08:00
|
|
|
if err := dec.Decode(&ierr); err != nil && err != io.EOF {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "decoding proc error from init")
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
if ierr != nil {
|
|
|
|
break loop
|
|
|
|
}
|
|
|
|
// Programmer error.
|
|
|
|
panic("No error following JSON procError payload.")
|
|
|
|
default:
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemError(fmt.Errorf("invalid JSON payload from child"))
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !sentRun {
|
2016-09-14 15:55:46 +08:00
|
|
|
return newSystemErrorWithCause(ierr, "container init")
|
2015-12-17 17:16:34 +08:00
|
|
|
}
|
2016-02-17 18:20:06 +08:00
|
|
|
if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume {
|
|
|
|
return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process"))
|
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
|
2016-04-19 02:37:26 +08:00
|
|
|
return newSystemErrorWithCause(err, "shutting down init pipe")
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
2015-12-17 17:16:34 +08:00
|
|
|
// Must be done after Shutdown so the child will exit and we can wait for it.
|
2015-02-07 13:12:27 +08:00
|
|
|
if ierr != nil {
|
2015-12-17 17:16:34 +08:00
|
|
|
p.wait()
|
2016-04-19 02:37:26 +08:00
|
|
|
return ierr
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) wait() (*os.ProcessState, error) {
|
2015-02-23 17:26:43 +08:00
|
|
|
err := p.cmd.Wait()
|
2015-02-07 13:12:27 +08:00
|
|
|
if err != nil {
|
2015-02-26 03:45:53 +08:00
|
|
|
return p.cmd.ProcessState, err
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
// we should kill all processes in cgroup when init is died if we use host PID namespace
|
2015-09-14 08:40:43 +08:00
|
|
|
if p.sharePidns {
|
2015-02-12 08:45:23 +08:00
|
|
|
killCgroupProcesses(p.manager)
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
2015-02-23 17:26:43 +08:00
|
|
|
return p.cmd.ProcessState, nil
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) terminate() error {
|
|
|
|
if p.cmd.Process == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
err := p.cmd.Process.Kill()
|
|
|
|
if _, werr := p.wait(); err == nil {
|
|
|
|
err = werr
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) startTime() (string, error) {
|
|
|
|
return system.GetProcessStartTime(p.pid())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) sendConfig() error {
|
2016-01-28 09:58:30 +08:00
|
|
|
// send the config to the container's init process, we don't use JSON Encode
|
|
|
|
// here because there might be a problem in JSON decoder in some cases, see:
|
|
|
|
// https://github.com/docker/docker/issues/14203#issuecomment-174177790
|
2016-01-26 10:15:44 +08:00
|
|
|
return utils.WriteJSON(p.parentPipe, p.config)
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *initProcess) createNetworkInterfaces() error {
|
|
|
|
for _, config := range p.config.Config.Networks {
|
2015-02-10 07:16:27 +08:00
|
|
|
strategy, err := getStrategy(config.Type)
|
2015-02-07 13:12:27 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-02-11 03:51:45 +08:00
|
|
|
n := &network{
|
|
|
|
Network: *config,
|
|
|
|
}
|
|
|
|
if err := strategy.create(n, p.pid()); err != nil {
|
2015-02-07 13:12:27 +08:00
|
|
|
return err
|
|
|
|
}
|
2015-02-11 03:51:45 +08:00
|
|
|
p.config.Networks = append(p.config.Networks, n)
|
2015-02-07 13:12:27 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-03-28 01:50:32 +08:00
|
|
|
func (p *initProcess) signal(sig os.Signal) error {
|
|
|
|
s, ok := sig.(syscall.Signal)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("os: unsupported signal type")
|
|
|
|
}
|
2015-09-23 10:48:36 +08:00
|
|
|
return syscall.Kill(p.pid(), s)
|
2015-02-07 14:33:10 +08:00
|
|
|
}
|
2015-04-29 04:54:03 +08:00
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
func (p *initProcess) setExternalDescriptors(newFds []string) {
|
2015-04-29 04:54:03 +08:00
|
|
|
p.fds = newFds
|
|
|
|
}
|
|
|
|
|
2015-04-29 19:52:17 +08:00
|
|
|
func getPipeFds(pid int) ([]string, error) {
|
2015-08-13 09:37:44 +08:00
|
|
|
fds := make([]string, 3)
|
2015-04-29 04:54:03 +08:00
|
|
|
|
|
|
|
dirPath := filepath.Join("/proc", strconv.Itoa(pid), "/fd")
|
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
f := filepath.Join(dirPath, strconv.Itoa(i))
|
|
|
|
target, err := os.Readlink(f)
|
|
|
|
if err != nil {
|
|
|
|
return fds, err
|
|
|
|
}
|
|
|
|
fds[i] = target
|
|
|
|
}
|
|
|
|
return fds, nil
|
|
|
|
}
|
2015-12-16 04:12:29 +08:00
|
|
|
|
|
|
|
// InitializeIO creates pipes for use with the process's STDIO
|
|
|
|
// and returns the opposite side for each
|
2016-04-23 21:39:38 +08:00
|
|
|
func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) {
|
2015-12-16 04:12:29 +08:00
|
|
|
var fds []uintptr
|
|
|
|
i = &IO{}
|
|
|
|
// cleanup in case of an error
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
for _, fd := range fds {
|
|
|
|
syscall.Close(int(fd))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
// STDIN
|
|
|
|
r, w, err := os.Pipe()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fds = append(fds, r.Fd(), w.Fd())
|
|
|
|
p.Stdin, i.Stdin = r, w
|
|
|
|
// STDOUT
|
|
|
|
if r, w, err = os.Pipe(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fds = append(fds, r.Fd(), w.Fd())
|
|
|
|
p.Stdout, i.Stdout = w, r
|
|
|
|
// STDERR
|
|
|
|
if r, w, err = os.Pipe(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fds = append(fds, r.Fd(), w.Fd())
|
|
|
|
p.Stderr, i.Stderr = w, r
|
|
|
|
// change ownership of the pipes incase we are in a user namespace
|
|
|
|
for _, fd := range fds {
|
2016-04-23 21:39:38 +08:00
|
|
|
if err := syscall.Fchown(int(fd), rootuid, rootgid); err != nil {
|
2015-12-16 04:12:29 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return i, nil
|
|
|
|
}
|