ContainerExecStart starts a previously set up exec instance. The std streams are set up. If ctx is cancelled, the process is terminated.
(ctx context.Context, name string, options backend.ExecStartConfig)
| 160 | // std streams are set up. |
| 161 | // If ctx is cancelled, the process is terminated. |
| 162 | func (daemon *Daemon) ContainerExecStart(ctx context.Context, name string, options backend.ExecStartConfig) (retErr error) { |
| 163 | var ( |
| 164 | cStdin io.ReadCloser |
| 165 | cStdout, cStderr io.Writer |
| 166 | ) |
| 167 | |
| 168 | ec, err := daemon.getExecConfig(name) |
| 169 | if err != nil { |
| 170 | return err |
| 171 | } |
| 172 | |
| 173 | ec.Lock() |
| 174 | if ec.ExitCode != nil { |
| 175 | ec.Unlock() |
| 176 | return errdefs.Conflict(fmt.Errorf("exec command %s has already run", ec.ID)) |
| 177 | } |
| 178 | |
| 179 | if ec.Running { |
| 180 | ec.Unlock() |
| 181 | return errdefs.Conflict(fmt.Errorf("exec command %s is already running", ec.ID)) |
| 182 | } |
| 183 | ec.Running = true |
| 184 | ec.Unlock() |
| 185 | |
| 186 | log.G(ctx).Debugf("starting exec command %s in container %s", ec.ID, ec.Container.ID) |
| 187 | daemon.LogContainerEventWithAttributes(ec.Container, events.Action(string(events.ActionExecStart)+": "+ec.Entrypoint+" "+strings.Join(ec.Args, " ")), map[string]string{ |
| 188 | "execID": ec.ID, |
| 189 | }) |
| 190 | |
| 191 | defer func() { |
| 192 | if retErr != nil { |
| 193 | ec.Lock() |
| 194 | ec.Container.ExecCommands.Delete(ec.ID) |
| 195 | ec.Running = false |
| 196 | if ec.ExitCode == nil { |
| 197 | // default to `126` (`EACCES`) if we fail to start |
| 198 | // the exec without setting an exit code. |
| 199 | exitCode := exitEaccess |
| 200 | ec.ExitCode = &exitCode |
| 201 | } |
| 202 | if err := ec.CloseStreams(); err != nil { |
| 203 | log.G(ctx).Errorf("failed to cleanup exec %s streams: %s", ec.Container.ID, err) |
| 204 | } |
| 205 | ec.Unlock() |
| 206 | } |
| 207 | }() |
| 208 | |
| 209 | if ec.OpenStdin && options.Stdin != nil { |
| 210 | r, w := io.Pipe() |
| 211 | go func() { |
| 212 | defer func() { |
| 213 | log.G(ctx).Debug("Closing buffered stdin pipe") |
| 214 | _ = w.Close() |
| 215 | }() |
| 216 | _, _ = pools.Copy(w, options.Stdin) |
| 217 | }() |
| 218 | cStdin = r |
| 219 | } |
nothing calls this directly
no test coverage detected