github.com/alexandrev/docker@v1.9.0/daemon/execdriver/native/exec.go (about)

     1  // +build linux
     2  
     3  package native
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"github.com/docker/docker/daemon/execdriver"
    13  	"github.com/opencontainers/runc/libcontainer"
    14  	// Blank import 'nsenter' so that init in that package will call c
    15  	// function 'nsexec()' to do 'setns' before Go runtime take over,
    16  	// it's used for join to exist ns like 'docker exec' command.
    17  	_ "github.com/opencontainers/runc/libcontainer/nsenter"
    18  	"github.com/opencontainers/runc/libcontainer/utils"
    19  )
    20  
    21  // Exec implements the exec driver Driver interface,
    22  // it calls libcontainer APIs to execute a container.
    23  func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
    24  	active := d.activeContainers[c.ID]
    25  	if active == nil {
    26  		return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
    27  	}
    28  
    29  	user := processConfig.User
    30  	if c.RemappedRoot.UID != 0 && user == "" {
    31  		//if user namespaces are enabled, set user explicitly so uid/gid is set to 0
    32  		//otherwise we end up with the overflow id and no permissions (65534)
    33  		user = "0"
    34  	}
    35  
    36  	p := &libcontainer.Process{
    37  		Args: append([]string{processConfig.Entrypoint}, processConfig.Arguments...),
    38  		Env:  c.ProcessConfig.Env,
    39  		Cwd:  c.WorkingDir,
    40  		User: user,
    41  	}
    42  
    43  	if processConfig.Privileged {
    44  		p.Capabilities = execdriver.GetAllCapabilities()
    45  	}
    46  	// add CAP_ prefix to all caps for new libcontainer update to match
    47  	// the spec format.
    48  	for i, s := range p.Capabilities {
    49  		if !strings.HasPrefix(s, "CAP_") {
    50  			p.Capabilities[i] = fmt.Sprintf("CAP_%s", s)
    51  		}
    52  	}
    53  
    54  	config := active.Config()
    55  	if err := setupPipes(&config, processConfig, p, pipes); err != nil {
    56  		return -1, err
    57  	}
    58  
    59  	if err := active.Start(p); err != nil {
    60  		return -1, err
    61  	}
    62  
    63  	if hooks.Start != nil {
    64  		pid, err := p.Pid()
    65  		if err != nil {
    66  			p.Signal(os.Kill)
    67  			p.Wait()
    68  			return -1, err
    69  		}
    70  
    71  		// A closed channel for OOM is returned here as it will be
    72  		// non-blocking and return the correct result when read.
    73  		chOOM := make(chan struct{})
    74  		close(chOOM)
    75  		hooks.Start(&c.ProcessConfig, pid, chOOM)
    76  	}
    77  
    78  	ps, err := p.Wait()
    79  	if err != nil {
    80  		exitErr, ok := err.(*exec.ExitError)
    81  		if !ok {
    82  			return -1, err
    83  		}
    84  		ps = exitErr.ProcessState
    85  	}
    86  	return utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), nil
    87  }