ContainerExecCreate sets up an exec in a running container.
(name string, options *containertypes.ExecCreateRequest)
| 94 | |
| 95 | // ContainerExecCreate sets up an exec in a running container. |
| 96 | func (daemon *Daemon) ContainerExecCreate(name string, options *containertypes.ExecCreateRequest) (string, error) { |
| 97 | cntr, err := daemon.getActiveContainer(name) |
| 98 | if err != nil { |
| 99 | return "", err |
| 100 | } |
| 101 | if user := options.User; user != "" { |
| 102 | // Lookup the user inside the container before starting the exec to |
| 103 | // allow for an early exit. |
| 104 | // |
| 105 | // Note that "technically" this check may have some TOCTOU issues, |
| 106 | // because '/etc/passwd' and '/etc/groups' may be mutated by the |
| 107 | // container in between creating the exec and starting it. |
| 108 | // |
| 109 | // This is very likely a corner-case, but something we can consider |
| 110 | // changing in future (either allow creating an invalid exec, and |
| 111 | // checking before starting, or checking both before create and |
| 112 | // before start). |
| 113 | if _, err := getUser(cntr, user); err != nil { |
| 114 | return "", errdefs.InvalidParameter(err) |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | keys := []byte{} |
| 119 | if options.DetachKeys != "" { |
| 120 | keys, err = term.ToBytes(options.DetachKeys) |
| 121 | if err != nil { |
| 122 | err = fmt.Errorf("Invalid escape keys (%s) provided", options.DetachKeys) |
| 123 | return "", err |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | execConfig := container.NewExecConfig(cntr) |
| 128 | execConfig.OpenStdin = options.AttachStdin |
| 129 | execConfig.OpenStdout = options.AttachStdout |
| 130 | execConfig.OpenStderr = options.AttachStderr |
| 131 | execConfig.DetachKeys = keys |
| 132 | execConfig.Entrypoint, execConfig.Args = options.Cmd[0], options.Cmd[1:] |
| 133 | execConfig.Tty = options.Tty |
| 134 | execConfig.ConsoleSize = options.ConsoleSize |
| 135 | execConfig.Privileged = options.Privileged |
| 136 | execConfig.User = options.User |
| 137 | execConfig.WorkingDir = options.WorkingDir |
| 138 | |
| 139 | linkedEnv, err := daemon.setupLinkedContainers(cntr) |
| 140 | if err != nil { |
| 141 | return "", err |
| 142 | } |
| 143 | execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(options.Tty, linkedEnv), options.Env) |
| 144 | if execConfig.User == "" { |
| 145 | execConfig.User = cntr.Config.User |
| 146 | } |
| 147 | if execConfig.WorkingDir == "" { |
| 148 | execConfig.WorkingDir = cntr.Config.WorkingDir |
| 149 | } |
| 150 | |
| 151 | daemon.registerExecCommand(cntr, execConfig) |
| 152 | daemon.LogContainerEventWithAttributes(cntr, events.Action(string(events.ActionExecCreate)+": "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")), map[string]string{ |
| 153 | "execID": execConfig.ID, |
nothing calls this directly
no test coverage detected