diff --git a/README.md b/README.md index ff86de882..c186d9a06 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,12 @@ docker pull base docker run -i -t base /bin/bash ``` +Detaching from the interactive shell +------------------------------------ +``` +# In order to detach without killing the shell, you can use the escape sequence Ctrl-p + Ctrl-q +# Note: this works only in tty mode (run with -t option). +``` Starting a long-running worker process -------------------------------------- diff --git a/container.go b/container.go index e5b2d0af4..f180c7559 100644 --- a/container.go +++ b/container.go @@ -255,7 +255,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s if container.Config.StdinOnce && !container.Config.Tty { defer cStdin.Close() } - _, err := io.Copy(cStdin, stdin) + if container.Config.Tty { + _, err = CopyEscapable(cStdin, stdin) + } else { + _, err = io.Copy(cStdin, stdin) + } if err != nil { Debugf("[error] attach stdin: %s\n", err) } diff --git a/term/termios_linux.go b/term/termios_linux.go index 5275ba87f..92f21edde 100644 --- a/term/termios_linux.go +++ b/term/termios_linux.go @@ -15,7 +15,8 @@ void MakeRaw(int fd) { ioctl(fd, TCGETS, &t); t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + t.c_oflag &= ~OPOST; + t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); t.c_cflag &= ~(CSIZE | PARENB); t.c_cflag |= CS8; diff --git a/utils.go b/utils.go index 5ee84239b..68e12b20b 100644 --- a/utils.go +++ b/utils.go @@ -341,3 +341,46 @@ func TruncateId(id string) string { } return id[:shortLen] } + +// Code c/c from io.Copy() modified to handle escape sequence +func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) { + buf := make([]byte, 32*1024) + for { + nr, er := src.Read(buf) + if nr > 0 { + // ---- Docker addition + // char 16 is C-p + if nr == 1 && buf[0] == 16 { + nr, er = src.Read(buf) + // char 17 is C-q + if nr == 1 && buf[0] == 17 { + if err := src.Close(); err != nil { + return 0, err + } + return 0, io.EOF + } + } + // ---- End of docker + nw, ew := dst.Write(buf[0:nr]) + if nw > 0 { + written += int64(nw) + } + if ew != nil { + err = ew + break + } + if nr != nw { + err = io.ErrShortWrite + break + } + } + if er == io.EOF { + break + } + if er != nil { + err = er + break + } + } + return written, err +}