2021-01-13 12:45:35 -05:00
|
|
|
package container
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
gosignal "os/signal"
|
|
|
|
|
|
|
|
"github.com/docker/cli/cli/command"
|
2021-08-09 13:15:46 -04:00
|
|
|
"github.com/moby/sys/signal"
|
2021-01-13 12:45:35 -05:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ForwardAllSignals forwards signals to the container
|
|
|
|
//
|
|
|
|
// The channel you pass in must already be setup to receive any signals you want to forward.
|
|
|
|
func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <-chan os.Signal) {
|
ForwardAllSignals: check if channel is closed, and remove warning
Commit fff164c22e8dc904291fecb62307312fd4ca153e modified ForwardAllSignals to
take `SIGURG` signals into account, which can be generated by the Go runtime
on Go 1.14 and up as an interrupt to support pre-emptable system calls on Linux.
With the updated code, the signal (`s`) would sometimes be `nil`, causing spurious
(but otherwise harmless) warnings to be printed;
Unsupported signal: <nil>. Discarding.
To debug this issue, I patched v20.10.4 to handle `nil`, and added a debug line
to print the signal in all cases;
```patch
diff --git a/cli/command/container/signals.go b/cli/command/container/signals.go
index 06e4d9eb6..0cb53ef06 100644
--- a/cli/command/container/signals.go
+++ b/cli/command/container/signals.go
@@ -22,8 +22,9 @@ func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <-
case <-ctx.Done():
return
}
+ fmt.Fprintf(cli.Err(), "Signal: %v\n", s)
if s == signal.SIGCHLD || s == signal.SIGPIPE {
```
When running a cross-compiled macOS binary with Go 1.13 (`make -f docker.Makefile binary-osx`):
# regular "docker run" (note that the `<nil>` signal only happens "sometimes"):
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
Signal: <nil>
# when cancelling with CTRL-C:
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
^CSignal: interrupt
Cloning into 'getting-started'...
error: could not lock config file /git/getting-started/.git/config: No such file or directory
fatal: could not set 'core.repositoryformatversion' to '0'
Signal: <nil>
Signal: <nil>
When running a macOS binary built with Go 1.15 (`DISABLE_WARN_OUTSIDE_CONTAINER=1 make binary`):
# regular "docker run" (note that the `<nil>` signal only happens "sometimes"):
# this is the same as on Go 1.13
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
Signal: <nil>
# when cancelling with CTRL-C:
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
^CSignal: interrupt
Signal: urgent I/O condition
Signal: urgent I/O condition
fatal: --stdin requires a git repository
fatal: index-pack failed
Signal: <nil>
Signal: <nil>
This patch checks if the channel is closed, and removes the warning (to prevent warnings if new
signals are added that are not in our known list of signals)
We should also consider updating `notfiyAllSignals()`, which currently forwards
_all_ signals (`signal.Notify(sigc)` without passing a list of signals), and
instead pass it "all signals _minus_ the signals we don't want forwarded":
https://github.com/docker/cli/blob/35f023a7c22a51867fb099d29006ef27379bc7fe/cli/command/container/signals.go#L55
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-03-01 08:06:19 -05:00
|
|
|
var (
|
|
|
|
s os.Signal
|
|
|
|
ok bool
|
|
|
|
)
|
2021-01-13 12:45:35 -05:00
|
|
|
for {
|
|
|
|
select {
|
ForwardAllSignals: check if channel is closed, and remove warning
Commit fff164c22e8dc904291fecb62307312fd4ca153e modified ForwardAllSignals to
take `SIGURG` signals into account, which can be generated by the Go runtime
on Go 1.14 and up as an interrupt to support pre-emptable system calls on Linux.
With the updated code, the signal (`s`) would sometimes be `nil`, causing spurious
(but otherwise harmless) warnings to be printed;
Unsupported signal: <nil>. Discarding.
To debug this issue, I patched v20.10.4 to handle `nil`, and added a debug line
to print the signal in all cases;
```patch
diff --git a/cli/command/container/signals.go b/cli/command/container/signals.go
index 06e4d9eb6..0cb53ef06 100644
--- a/cli/command/container/signals.go
+++ b/cli/command/container/signals.go
@@ -22,8 +22,9 @@ func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <-
case <-ctx.Done():
return
}
+ fmt.Fprintf(cli.Err(), "Signal: %v\n", s)
if s == signal.SIGCHLD || s == signal.SIGPIPE {
```
When running a cross-compiled macOS binary with Go 1.13 (`make -f docker.Makefile binary-osx`):
# regular "docker run" (note that the `<nil>` signal only happens "sometimes"):
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
Signal: <nil>
# when cancelling with CTRL-C:
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
^CSignal: interrupt
Cloning into 'getting-started'...
error: could not lock config file /git/getting-started/.git/config: No such file or directory
fatal: could not set 'core.repositoryformatversion' to '0'
Signal: <nil>
Signal: <nil>
When running a macOS binary built with Go 1.15 (`DISABLE_WARN_OUTSIDE_CONTAINER=1 make binary`):
# regular "docker run" (note that the `<nil>` signal only happens "sometimes"):
# this is the same as on Go 1.13
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
Signal: <nil>
# when cancelling with CTRL-C:
./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git
Cloning into 'getting-started'...
^CSignal: interrupt
Signal: urgent I/O condition
Signal: urgent I/O condition
fatal: --stdin requires a git repository
fatal: index-pack failed
Signal: <nil>
Signal: <nil>
This patch checks if the channel is closed, and removes the warning (to prevent warnings if new
signals are added that are not in our known list of signals)
We should also consider updating `notfiyAllSignals()`, which currently forwards
_all_ signals (`signal.Notify(sigc)` without passing a list of signals), and
instead pass it "all signals _minus_ the signals we don't want forwarded":
https://github.com/docker/cli/blob/35f023a7c22a51867fb099d29006ef27379bc7fe/cli/command/container/signals.go#L55
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-03-01 08:06:19 -05:00
|
|
|
case s, ok = <-sigc:
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
2021-01-13 12:45:35 -05:00
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// In go1.14+, the go runtime issues SIGURG as an interrupt to support pre-emptable system calls on Linux.
|
|
|
|
// Since we can't forward that along we'll check that here.
|
|
|
|
if isRuntimeSig(s) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
var sig string
|
|
|
|
for sigStr, sigN := range signal.SignalMap {
|
|
|
|
if sigN == s {
|
|
|
|
sig = sigStr
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if sig == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
|
|
|
|
logrus.Debugf("Error sending signal: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func notfiyAllSignals() chan os.Signal {
|
|
|
|
sigc := make(chan os.Signal, 128)
|
|
|
|
gosignal.Notify(sigc)
|
|
|
|
return sigc
|
|
|
|
}
|