diff options
author | Matthew Heon <matthew.heon@pm.me> | 2020-09-10 17:28:22 -0400 |
---|---|---|
committer | Matthew Heon <matthew.heon@pm.me> | 2020-09-10 17:54:47 -0400 |
commit | 4c155d36cba90fd07f75c6d7d6f09848b88dac4a (patch) | |
tree | 79f3534c22c26e493e9ac01e519a61cb740ca486 | |
parent | 1184cdf03d8464451d36b24643e57b65a8b97980 (diff) | |
download | podman-4c155d36cba90fd07f75c6d7d6f09848b88dac4a.tar.gz podman-4c155d36cba90fd07f75c6d7d6f09848b88dac4a.tar.bz2 podman-4c155d36cba90fd07f75c6d7d6f09848b88dac4a.zip |
Force Attach() to send a SIGWINCH and redraw
Basically, we want to force the application in the container to
(iff the container was made with a terminal) redraw said terminal
immediately after an attach completes, so the fresh Attach
session will be able to see what's going on (e.g. will have a
shell prompt). Our current attach functions are unfortunately
geared more towards `podman run` than `podman attach` and will
start forwarding resize events *immediately* instead of waiting
until the attach session is alive (much safer for short-lived
`podman run` sessions, but broken for the `podman attach` case).
To avoid a major rewrite, let's just manually send a SIGWINCH
after attach succeeds to force a redraw.
Fixes #6253
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
-rw-r--r-- | libpod/container_api.go | 20 | ||||
-rw-r--r-- | libpod/oci_attach_linux.go | 5 | ||||
-rw-r--r-- | libpod/oci_attach_unsupported.go | 2 |
3 files changed, 23 insertions, 4 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go index 0d7bbacd0..aef37dd59 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/events" + "github.com/containers/podman/v2/pkg/signal" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -129,7 +130,7 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachSt // Attach to the container before starting it go func() { - if err := c.attach(streams, keys, resize, true, startedChan); err != nil { + if err := c.attach(streams, keys, resize, true, startedChan, nil); err != nil { attachChan <- err } close(attachChan) @@ -243,8 +244,23 @@ func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <- return errors.Wrapf(define.ErrCtrStateInvalid, "can only attach to created or running containers") } + // HACK: This is really gross, but there isn't a better way without + // splitting attach into separate versions for StartAndAttach and normal + // attaching, and I really do not want to do that right now. + // Send a SIGWINCH after attach succeeds so that most programs will + // redraw the screen for the new attach session. + attachRdy := make(chan bool) + if c.config.Spec.Process != nil && c.config.Spec.Process.Terminal { + go func() { + <-attachRdy + if err := c.ociRuntime.KillContainer(c, uint(signal.SIGWINCH), false); err != nil { + logrus.Warnf("Unable to send SIGWINCH to container %s after attach: %v", c.ID(), err) + } + }() + } + c.newContainerEvent(events.Attach) - return c.attach(streams, keys, resize, false, nil) + return c.attach(streams, keys, resize, false, nil, attachRdy) } // HTTPAttach forwards an attach session over a hijacked HTTP session. diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go index 622c613d9..74af449ed 100644 --- a/libpod/oci_attach_linux.go +++ b/libpod/oci_attach_linux.go @@ -31,7 +31,7 @@ const ( // Attach to the given container // Does not check if state is appropriate // started is only required if startContainer is true -func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error { +func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool, attachRdy chan<- bool) error { if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput { return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to") } @@ -74,6 +74,9 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <- } receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys) + if attachRdy != nil { + attachRdy <- true + } return readStdio(streams, receiveStdoutError, stdinDone) } diff --git a/libpod/oci_attach_unsupported.go b/libpod/oci_attach_unsupported.go index cd7c674b2..317dfdc90 100644 --- a/libpod/oci_attach_unsupported.go +++ b/libpod/oci_attach_unsupported.go @@ -9,7 +9,7 @@ import ( "k8s.io/client-go/tools/remotecommand" ) -func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error { +func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool, attachRdy chan<- bool) error { return define.ErrNotImplemented } |