diff --git a/api/server/container.go b/api/server/container.go
index 3af7972674..87b1998541 100644
--- a/api/server/container.go
+++ b/api/server/container.go
@@ -6,6 +6,7 @@ import (
"net/http"
"strconv"
"strings"
+ "syscall"
"time"
"golang.org/x/net/websocket"
@@ -220,32 +221,18 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
return err
}
- var sig uint64
+ var sig syscall.Signal
name := vars["name"]
// If we have a signal, look at it. Otherwise, do nothing
if sigStr := r.Form.Get("signal"); sigStr != "" {
- // Check if we passed the signal as a number:
- // The largest legal signal is 31, so let's parse on 5 bits
- sigN, err := strconv.ParseUint(sigStr, 10, 5)
- if err != nil {
- // The signal is not a number, treat it as a string (either like
- // "KILL" or like "SIGKILL")
- syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
- if !ok {
- return fmt.Errorf("Invalid signal: %s", sigStr)
- }
- sig = uint64(syscallSig)
- } else {
- sig = sigN
- }
-
- if sig == 0 {
- return fmt.Errorf("Invalid signal: %s", sigStr)
+ var err error
+ if sig, err = signal.ParseSignal(sigStr); err != nil {
+ return err
}
}
- if err := s.daemon.ContainerKill(name, sig); err != nil {
+ if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
_, isStopped := err.(daemon.ErrContainerNotRunning)
// Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20
diff --git a/builder/command/command.go b/builder/command/command.go
index 93b1c8bd81..968dba1f8d 100644
--- a/builder/command/command.go
+++ b/builder/command/command.go
@@ -17,6 +17,7 @@ const (
Expose = "expose"
Volume = "volume"
User = "user"
+ StopSignal = "stopsignal"
)
// Commands is list of all Dockerfile commands
@@ -35,4 +36,5 @@ var Commands = map[string]struct{}{
Expose: {},
Volume: {},
User: {},
+ StopSignal: {},
}
diff --git a/builder/dispatchers.go b/builder/dispatchers.go
index 78e3f87229..b00001260f 100644
--- a/builder/dispatchers.go
+++ b/builder/dispatchers.go
@@ -20,6 +20,7 @@ import (
"github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat"
+ "github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig"
@@ -534,3 +535,21 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
}
return nil
}
+
+// STOPSIGNAL signal
+//
+// Set the signal that will be used to kill the container.
+func stopSignal(b *builder, args []string, attributes map[string]bool, original string) error {
+ if len(args) != 1 {
+ return fmt.Errorf("STOPSIGNAL requires exactly one argument")
+ }
+
+ sig := args[0]
+ _, err := signal.ParseSignal(sig)
+ if err != nil {
+ return err
+ }
+
+ b.Config.StopSignal = sig
+ return b.commit("", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
+}
diff --git a/builder/evaluator.go b/builder/evaluator.go
index 2b0c038a01..18d2c36a63 100644
--- a/builder/evaluator.go
+++ b/builder/evaluator.go
@@ -45,14 +45,15 @@ import (
// Environment variable interpolation will happen on these statements only.
var replaceEnvAllowed = map[string]struct{}{
- command.Env: {},
- command.Label: {},
- command.Add: {},
- command.Copy: {},
- command.Workdir: {},
- command.Expose: {},
- command.Volume: {},
- command.User: {},
+ command.Env: {},
+ command.Label: {},
+ command.Add: {},
+ command.Copy: {},
+ command.Workdir: {},
+ command.Expose: {},
+ command.Volume: {},
+ command.User: {},
+ command.StopSignal: {},
}
var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error
@@ -73,6 +74,7 @@ func init() {
command.Expose: expose,
command.Volume: volume,
command.User: user,
+ command.StopSignal: stopSignal,
}
}
diff --git a/builder/parser/parser.go b/builder/parser/parser.go
index c72d9df4d8..37548401d3 100644
--- a/builder/parser/parser.go
+++ b/builder/parser/parser.go
@@ -61,6 +61,7 @@ func init() {
command.Entrypoint: parseMaybeJSON,
command.Expose: parseStringsWhitespaceDelimited,
command.Volume: parseMaybeJSONToList,
+ command.StopSignal: parseString,
}
}
diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker
index 4b8d9bd209..9d63416c4b 100644
--- a/contrib/completion/bash/docker
+++ b/contrib/completion/bash/docker
@@ -1149,6 +1149,7 @@ _docker_run() {
--publish -p
--restart
--security-opt
+ --stop-signal
--ulimit
--user -u
--uts
diff --git a/contrib/completion/fish/docker.fish b/contrib/completion/fish/docker.fish
index 9a32f8c64e..7dcc554139 100644
--- a/contrib/completion/fish/docker.fish
+++ b/contrib/completion/fish/docker.fish
@@ -335,6 +335,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l restart -d 'Res
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.'
+complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l stop-signal 'Signal to kill a container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)'
diff --git a/contrib/completion/zsh/_docker b/contrib/completion/zsh/_docker
index fc894c84b5..448dac9d59 100644
--- a/contrib/completion/zsh/_docker
+++ b/contrib/completion/zsh/_docker
@@ -502,6 +502,7 @@ __docker_subcommand() {
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help)--rm[Remove intermediate containers when it exits]" \
"($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \
+ "($help)--stop-signal[Signal to kill a container]" \
"($help -): :__docker_images" \
"($help -):command: _command_names -e" \
"($help -)*::arguments: _normal" && ret=0
diff --git a/contrib/syntax/kate/Dockerfile.xml b/contrib/syntax/kate/Dockerfile.xml
index 4fdef2393b..05692504e7 100644
--- a/contrib/syntax/kate/Dockerfile.xml
+++ b/contrib/syntax/kate/Dockerfile.xml
@@ -23,6 +23,7 @@
- WORKDIR
- USER
- LABEL
+ - STOPSIGNAL
diff --git a/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage b/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage
index 61e45ccbf6..0ca231c319 100644
--- a/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage
+++ b/contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage
@@ -25,7 +25,7 @@
match
- ^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL)\s
+ ^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL|STOPSIGNAL)\s
captures
diff --git a/contrib/syntax/vim/syntax/dockerfile.vim b/contrib/syntax/vim/syntax/dockerfile.vim
index 220a4db3a2..3cb1ecfddf 100644
--- a/contrib/syntax/vim/syntax/dockerfile.vim
+++ b/contrib/syntax/vim/syntax/dockerfile.vim
@@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
syntax case ignore
-syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY)\s/
+syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY|STOPSIGNAL)\s/
highlight link dockerfileKeyword Keyword
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
diff --git a/daemon/container.go b/daemon/container.go
index bd622b8780..c73e7aadb7 100644
--- a/daemon/container.go
+++ b/daemon/container.go
@@ -27,6 +27,7 @@ import (
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/promise"
+ "github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
@@ -495,10 +496,10 @@ func (container *Container) Kill() error {
return nil
}
-// Stop halts a container by sending SIGTERM, waiting for the given
+// Stop halts a container by sending a stop signal, waiting for the given
// duration in seconds, and then calling SIGKILL and waiting for the
// process to exit. If a negative duration is given, Stop will wait
-// for SIGTERM forever. If the container is not running Stop returns
+// for the initial signal forever. If the container is not running Stop returns
// immediately.
func (container *Container) Stop(seconds int) error {
if !container.IsRunning() {
@@ -506,9 +507,9 @@ func (container *Container) Stop(seconds int) error {
}
// 1. Send a SIGTERM
- if err := container.killPossiblyDeadProcess(int(syscall.SIGTERM)); err != nil {
+ if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil {
logrus.Infof("Failed to send SIGTERM to the process, force killing")
- if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil {
+ if err := container.killPossiblyDeadProcess(9); err != nil {
return err
}
}
@@ -1140,3 +1141,15 @@ func (container *Container) copyImagePathContent(v volume.Volume, destination st
return v.Unmount()
}
+
+func (container *Container) stopSignal() int {
+ var stopSignal syscall.Signal
+ if container.Config.StopSignal != "" {
+ stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
+ }
+
+ if int(stopSignal) == 0 {
+ stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal)
+ }
+ return int(stopSignal)
+}
diff --git a/daemon/container_unit_test.go b/daemon/container_unit_test.go
index ab30a8e373..71d37cf436 100644
--- a/daemon/container_unit_test.go
+++ b/daemon/container_unit_test.go
@@ -1,6 +1,11 @@
package daemon
-import "testing"
+import (
+ "testing"
+
+ "github.com/docker/docker/pkg/signal"
+ "github.com/docker/docker/runconfig"
+)
func TestGetFullName(t *testing.T) {
name, err := GetFullContainerName("testing")
@@ -31,3 +36,31 @@ func TestValidContainerNames(t *testing.T) {
}
}
}
+
+func TestContainerStopSignal(t *testing.T) {
+ c := &Container{
+ CommonContainer: CommonContainer{
+ Config: &runconfig.Config{},
+ },
+ }
+
+ def, err := signal.ParseSignal(signal.DefaultStopSignal)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ s := c.stopSignal()
+ if s != int(def) {
+ t.Fatalf("Expected %v, got %v", def, s)
+ }
+
+ c = &Container{
+ CommonContainer: CommonContainer{
+ Config: &runconfig.Config{StopSignal: "SIGKILL"},
+ },
+ }
+ s = c.stopSignal()
+ if s != 9 {
+ t.Fatalf("Expected 9, got %v", s)
+ }
+}
diff --git a/daemon/daemon.go b/daemon/daemon.go
index f5a0c035f3..3dcf93b629 100644
--- a/daemon/daemon.go
+++ b/daemon/daemon.go
@@ -1076,6 +1076,13 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir)
}
}
+
+ if len(config.StopSignal) > 0 {
+ _, err := signal.ParseSignal(config.StopSignal)
+ if err != nil {
+ return nil, err
+ }
+ }
}
if hostConfig == nil {
diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md
index 1e1ff2d5c8..0d09f5c4ef 100644
--- a/docs/reference/api/docker_remote_api.md
+++ b/docs/reference/api/docker_remote_api.md
@@ -82,6 +82,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `DELETE /volumes/(name)`remove a volume with the specified name.
* `VolumeDriver` has been moved from config to hostConfig to make the configuration portable.
* `GET /images/(name)/json` now returns information about tags of the image.
+* The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container.
### v1.20 API changes
diff --git a/docs/reference/api/docker_remote_api_v1.21.md b/docs/reference/api/docker_remote_api_v1.21.md
index 6a9e37faf1..4fdb330010 100644
--- a/docs/reference/api/docker_remote_api_v1.21.md
+++ b/docs/reference/api/docker_remote_api_v1.21.md
@@ -166,6 +166,7 @@ Create a container
"ExposedPorts": {
"22/tcp": {}
},
+ "StopSignal": "SIGTERM",
"HostConfig": {
"Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"],
@@ -250,6 +251,7 @@ Json Parameters:
container
- **ExposedPorts** - An object mapping ports to an empty object in the form of:
`"ExposedPorts": { "/: {}" }`
+- **StopSignal** - Signal to stop a container as a string or unsigned integer. `SIGTERM` by default.
- **HostConfig**
- **Binds** – A list of volume bindings for this container. Each volume binding is a string in one of these forms:
+ `container_path` to create a new volume for the container
@@ -367,7 +369,8 @@ Return low-level information on the container `id`
"Tty": false,
"User": "",
"Volumes": null,
- "WorkingDir": ""
+ "WorkingDir": "",
+ "StopSignal": "SIGTERM"
},
"Created": "2015-01-06T15:47:31.485331387Z",
"Driver": "devicemapper",
diff --git a/docs/reference/builder.md b/docs/reference/builder.md
index 3a73b87d29..195139758f 100644
--- a/docs/reference/builder.md
+++ b/docs/reference/builder.md
@@ -158,6 +158,7 @@ the `Dockerfile`:
* `USER`
* `WORKDIR`
* `VOLUME`
+* `STOPSIGNAL`
as well as:
@@ -1012,6 +1013,14 @@ For example you might add something like this:
> **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions.
+## STOPSIGNAL
+
+ STOPSIGNAL signal
+
+The `STOPSIGNAL` instruction sets the system call signal that will be sent to the container to exit.
+This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
+or a signal name in the format SIGNAME, for instance SIGKILL.
+
## Dockerfile examples
# Nginx
diff --git a/docs/reference/commandline/create.md b/docs/reference/commandline/create.md
index 74d5185a34..7c64d7297d 100644
--- a/docs/reference/commandline/create.md
+++ b/docs/reference/commandline/create.md
@@ -61,6 +61,7 @@ Creates a new container.
--read-only=false Mount the container's root filesystem as read only
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
--security-opt=[] Security options
+ --stop-signal="SIGTERM" Signal to stop a container
-t, --tty=false Allocate a pseudo-TTY
--disable-content-trust=true Skip image verification
-u, --user="" Username or UID
diff --git a/docs/reference/commandline/run.md b/docs/reference/commandline/run.md
index 6ee97906d9..c7726497cc 100644
--- a/docs/reference/commandline/run.md
+++ b/docs/reference/commandline/run.md
@@ -62,6 +62,7 @@ weight=1
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
--rm=false Automatically remove the container when it exits
--security-opt=[] Security Options
+ --stop-signal="SIGTERM" Signal to stop a container
--sig-proxy=true Proxy received signals to the process
-t, --tty=false Allocate a pseudo-TTY
-u, --user="" Username or UID (format: [:])
@@ -531,3 +532,9 @@ containers with `daemon` user:
The 4th container fails and reports "[8] System error: resource temporarily unavailable" error.
This fails because the caller set `nproc=3` resulting in the first three containers using up
the three processes quota set for the `daemon` user.
+
+### Stopping a container with a specific signal
+
+The `--stop-signal` flag sets the system call signal that will be sent to the container to exit.
+This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
+or a signal name in the format SIGNAME, for instance SIGKILL.
diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go
index 1e5ef40148..308e9407a7 100644
--- a/integration-cli/docker_cli_build_test.go
+++ b/integration-cli/docker_cli_build_test.go
@@ -5660,3 +5660,18 @@ func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
_, err = buildImageFromContext(name, ctx, true)
c.Assert(err, check.IsNil)
}
+
+func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
+ name := "test_build_stop_signal"
+ _, err := buildImage(name,
+ `FROM busybox
+ STOPSIGNAL SIGKILL`,
+ true)
+ c.Assert(err, check.IsNil)
+ res, err := inspectFieldJSON(name, "Config.StopSignal")
+ c.Assert(err, check.IsNil)
+
+ if res != `"SIGKILL"` {
+ c.Fatalf("Signal %s, expected SIGKILL", res)
+ }
+}
diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go
index f854d0d6fe..ac36320848 100644
--- a/integration-cli/docker_cli_create_test.go
+++ b/integration-cli/docker_cli_create_test.go
@@ -458,3 +458,15 @@ func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
c.Fatalf("Missing expected output on trusted push:\n%s", out)
}
}
+
+func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
+ name := "test_create_stop_signal"
+ dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
+
+ res, err := inspectFieldJSON(name, "Config.StopSignal")
+ c.Assert(err, check.IsNil)
+
+ if res != `"9"` {
+ c.Fatalf("Expected 9, got %s", res)
+ }
+}
diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go
index 9ca05145e8..d3ddace8db 100644
--- a/integration-cli/docker_cli_run_unix_test.go
+++ b/integration-cli/docker_cli_run_unix_test.go
@@ -315,3 +315,19 @@ func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) {
c.Fatalf("failed. test was able to set invalid value, output: %q", out)
}
}
+
+func (s *DockerSuite) TestStopContainerSignal(c *check.C) {
+ out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`)
+ containerID := strings.TrimSpace(out)
+
+ if err := waitRun(containerID); err != nil {
+ c.Fatal(err)
+ }
+
+ dockerCmd(c, "stop", containerID)
+ out, _ = dockerCmd(c, "logs", containerID)
+
+ if !strings.Contains(out, "exit trapped") {
+ c.Fatalf("Expected `exit trapped` in the log, got %v", out)
+ }
+}
diff --git a/man/docker-create.1.md b/man/docker-create.1.md
index 9385c882be..d040e62b7b 100644
--- a/man/docker-create.1.md
+++ b/man/docker-create.1.md
@@ -51,6 +51,7 @@ docker-create - Create a new container
[**--read-only**[=*false*]]
[**--restart**[=*RESTART*]]
[**--security-opt**[=*[]*]]
+[**--stop-signal**[=*SIGNAL*]]
[**-t**|**--tty**[=*false*]]
[**-u**|**--user**[=*USER*]]
[**--ulimit**[=*[]*]]
@@ -239,6 +240,9 @@ This value should always larger than **-m**, so you should always use this with
**--security-opt**=[]
Security Options
+**--stop-signal**=SIGTERM
+ Signal to stop a container. Default is SIGTERM.
+
**-t**, **--tty**=*true*|*false*
Allocate a pseudo-TTY. The default is *false*.
diff --git a/man/docker-inspect.1.md b/man/docker-inspect.1.md
index a1bbb317a9..f7faf4a7b2 100644
--- a/man/docker-inspect.1.md
+++ b/man/docker-inspect.1.md
@@ -180,7 +180,8 @@ To get information on a container use its ID or instance name:
"Memory": 0,
"MemorySwap": 0,
"CpuShares": 0,
- "Cpuset": ""
+ "Cpuset": "",
+ "StopSignal": "SIGTERM"
}
}
]
diff --git a/man/docker-run.1.md b/man/docker-run.1.md
index 0bb339d34e..b37d07b0e9 100644
--- a/man/docker-run.1.md
+++ b/man/docker-run.1.md
@@ -53,6 +53,7 @@ docker-run - Run a command in a new container
[**--restart**[=*RESTART*]]
[**--rm**[=*false*]]
[**--security-opt**[=*[]*]]
+[**--stop-signal**[=*SIGNAL*]]
[**--sig-proxy**[=*true*]]
[**-t**|**--tty**[=*false*]]
[**-u**|**--user**[=*USER*]]
@@ -371,7 +372,7 @@ its root filesystem mounted as read only prohibiting any writes.
**--restart**="no"
Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
-
+
**--rm**=*true*|*false*
Automatically remove the container when it exits (incompatible with -d). The default is *false*.
@@ -384,6 +385,9 @@ its root filesystem mounted as read only prohibiting any writes.
"label:level:LEVEL" : Set the label level for the container
"label:disable" : Turn off label confinement for the container
+**--stop-signal**=SIGTERM
+ Signal to stop a container. Default is SIGTERM.
+
**--sig-proxy**=*true*|*false*
Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*.
diff --git a/man/docker-stop.1.md b/man/docker-stop.1.md
index 9b882db49d..4939070d97 100644
--- a/man/docker-stop.1.md
+++ b/man/docker-stop.1.md
@@ -19,7 +19,7 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
Print usage statement
**-t**, **--time**=10
- Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.
+ Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.
#See also
**docker-start(1)** to restart a stopped container.
diff --git a/pkg/signal/signal.go b/pkg/signal/signal.go
index db60bf2e59..106fe20d74 100644
--- a/pkg/signal/signal.go
+++ b/pkg/signal/signal.go
@@ -3,8 +3,12 @@
package signal
import (
+ "fmt"
"os"
"os/signal"
+ "strconv"
+ "strings"
+ "syscall"
)
// CatchAll catches all signals and relays them to the specified channel.
@@ -21,3 +25,20 @@ func StopCatch(sigc chan os.Signal) {
signal.Stop(sigc)
close(sigc)
}
+
+// ParseSignal translates a string to a valid syscall signal.
+// It returns an error if the signal map doesn't include the given signal.
+func ParseSignal(rawSignal string) (syscall.Signal, error) {
+ s, err := strconv.Atoi(rawSignal)
+ if err == nil {
+ if s == 0 {
+ return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
+ }
+ return syscall.Signal(s), nil
+ }
+ signal, ok := SignalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
+ if !ok {
+ return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
+ }
+ return signal, nil
+}
diff --git a/pkg/signal/signal_unix.go b/pkg/signal/signal_unix.go
index 5c1ad5f722..d4fea931d1 100644
--- a/pkg/signal/signal_unix.go
+++ b/pkg/signal/signal_unix.go
@@ -9,8 +9,11 @@ import (
// Signals used in api/client (no windows equivalent, use
// invalid signals so they don't get handled)
-// SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
-const SIGCHLD = syscall.SIGCHLD
-
-// SIGWINCH is a signal sent to a process when its controlling terminal changes its size
-const SIGWINCH = syscall.SIGWINCH
+const (
+ // SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
+ SIGCHLD = syscall.SIGCHLD
+ // SIGWINCH is a signal sent to a process when its controlling terminal changes its size
+ SIGWINCH = syscall.SIGWINCH
+ // DefaultStopSignal is the syscall signal used to stop a container in unix systems.
+ DefaultStopSignal = "SIGTERM"
+)
diff --git a/pkg/signal/signal_windows.go b/pkg/signal/signal_windows.go
index 1f1a6edbfc..b0585b0ed9 100644
--- a/pkg/signal/signal_windows.go
+++ b/pkg/signal/signal_windows.go
@@ -11,4 +11,6 @@ import (
const (
SIGCHLD = syscall.Signal(0xff)
SIGWINCH = syscall.Signal(0xff)
+ // DefaultStopSignal is the syscall signal used to stop a container in windows systems.
+ DefaultStopSignal = "15"
)
diff --git a/runconfig/config.go b/runconfig/config.go
index 04010954be..16a2f95b26 100644
--- a/runconfig/config.go
+++ b/runconfig/config.go
@@ -34,6 +34,7 @@ type Config struct {
MacAddress string // Mac Address of the container
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
Labels map[string]string // List of labels set to this container
+ StopSignal string // Signal to stop a container
}
// DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper
diff --git a/runconfig/parse.go b/runconfig/parse.go
index 8850b9f46c..079dff728e 100644
--- a/runconfig/parse.go
+++ b/runconfig/parse.go
@@ -9,6 +9,7 @@ import (
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/parsers"
+ "github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/units"
)
@@ -93,6 +94,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flLoggingDriver = cmd.String([]string{"-log-driver"}, "", "Logging driver for container")
flCgroupParent = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container")
+ flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
)
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR")
@@ -322,6 +324,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
Entrypoint: entrypoint,
WorkingDir: *flWorkingDir,
Labels: convertKVStringsToMap(labels),
+ StopSignal: *flStopSignal,
}
hostConfig := &HostConfig{