2014-09-04 01:29:19 -04:00
|
|
|
// +build linux
|
|
|
|
|
|
|
|
package native
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2015-09-21 19:06:08 -04:00
|
|
|
"strings"
|
2015-03-05 12:55:14 -05:00
|
|
|
"syscall"
|
2014-09-04 01:29:19 -04:00
|
|
|
|
2014-09-09 00:19:32 -04:00
|
|
|
"github.com/docker/docker/daemon/execdriver"
|
2015-07-16 19:00:55 -04:00
|
|
|
"github.com/opencontainers/runc/libcontainer"
|
2015-07-27 20:43:22 -04:00
|
|
|
// Blank import 'nsenter' so that init in that package will call c
|
|
|
|
// function 'nsexec()' to do 'setns' before Go runtime take over,
|
|
|
|
// it's used for join to exist ns like 'docker exec' command.
|
2015-07-16 19:00:55 -04:00
|
|
|
_ "github.com/opencontainers/runc/libcontainer/nsenter"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/utils"
|
2014-09-04 01:29:19 -04:00
|
|
|
)
|
|
|
|
|
2015-07-27 20:43:22 -04:00
|
|
|
// Exec implements the exec driver Driver interface,
|
|
|
|
// it calls libcontainer APIs to execute a container.
|
2015-09-29 13:51:40 -04:00
|
|
|
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
2014-09-04 01:29:19 -04:00
|
|
|
active := d.activeContainers[c.ID]
|
|
|
|
if active == nil {
|
|
|
|
return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
|
|
|
|
}
|
|
|
|
|
2015-10-08 11:51:41 -04:00
|
|
|
user := processConfig.User
|
|
|
|
if c.RemappedRoot.UID != 0 && user == "" {
|
|
|
|
//if user namespaces are enabled, set user explicitly so uid/gid is set to 0
|
|
|
|
//otherwise we end up with the overflow id and no permissions (65534)
|
|
|
|
user = "0"
|
|
|
|
}
|
|
|
|
|
2015-03-05 12:55:14 -05:00
|
|
|
p := &libcontainer.Process{
|
|
|
|
Args: append([]string{processConfig.Entrypoint}, processConfig.Arguments...),
|
|
|
|
Env: c.ProcessConfig.Env,
|
|
|
|
Cwd: c.WorkingDir,
|
2015-10-08 11:51:41 -04:00
|
|
|
User: user,
|
2015-03-05 12:55:14 -05:00
|
|
|
}
|
2014-09-04 01:29:19 -04:00
|
|
|
|
2015-06-19 02:01:50 -04:00
|
|
|
if processConfig.Privileged {
|
|
|
|
p.Capabilities = execdriver.GetAllCapabilities()
|
|
|
|
}
|
2015-09-21 19:06:08 -04:00
|
|
|
// add CAP_ prefix to all caps for new libcontainer update to match
|
|
|
|
// the spec format.
|
|
|
|
for i, s := range p.Capabilities {
|
|
|
|
if !strings.HasPrefix(s, "CAP_") {
|
|
|
|
p.Capabilities[i] = fmt.Sprintf("CAP_%s", s)
|
|
|
|
}
|
|
|
|
}
|
2015-06-19 02:01:50 -04:00
|
|
|
|
2015-04-22 19:37:15 -04:00
|
|
|
config := active.Config()
|
|
|
|
if err := setupPipes(&config, processConfig, p, pipes); err != nil {
|
2015-03-05 12:55:14 -05:00
|
|
|
return -1, err
|
2014-09-04 01:29:19 -04:00
|
|
|
}
|
|
|
|
|
2015-03-05 12:55:14 -05:00
|
|
|
if err := active.Start(p); err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
|
2015-09-11 15:05:57 -04:00
|
|
|
if hooks.Start != nil {
|
2015-03-05 12:55:14 -05:00
|
|
|
pid, err := p.Pid()
|
|
|
|
if err != nil {
|
|
|
|
p.Signal(os.Kill)
|
|
|
|
p.Wait()
|
|
|
|
return -1, err
|
|
|
|
}
|
2015-09-11 06:01:47 -04:00
|
|
|
|
|
|
|
// A closed channel for OOM is returned here as it will be
|
|
|
|
// non-blocking and return the correct result when read.
|
|
|
|
chOOM := make(chan struct{})
|
|
|
|
close(chOOM)
|
2015-09-29 13:51:40 -04:00
|
|
|
hooks.Start(&c.ProcessConfig, pid, chOOM)
|
2015-03-05 12:55:14 -05:00
|
|
|
}
|
2014-09-04 01:29:19 -04:00
|
|
|
|
2015-03-05 12:55:14 -05:00
|
|
|
ps, err := p.Wait()
|
|
|
|
if err != nil {
|
|
|
|
exitErr, ok := err.(*exec.ExitError)
|
|
|
|
if !ok {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
ps = exitErr.ProcessState
|
|
|
|
}
|
|
|
|
return utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), nil
|
2014-09-04 01:29:19 -04:00
|
|
|
}
|