| ... | ... |
@@ -134,6 +134,12 @@ docker pull base |
| 134 | 134 |
docker run -i -t base /bin/bash |
| 135 | 135 |
``` |
| 136 | 136 |
|
| 137 |
+Detaching from the interactive shell |
|
| 138 |
+------------------------------------ |
|
| 139 |
+``` |
|
| 140 |
+# In order to detach without killing the shell, you can use the escape sequence Ctrl-p + Ctrl-q |
|
| 141 |
+# Note: this works only in tty mode (run with -t option). |
|
| 142 |
+``` |
|
| 137 | 143 |
|
| 138 | 144 |
Starting a long-running worker process |
| 139 | 145 |
-------------------------------------- |
| ... | ... |
@@ -255,7 +255,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 255 | 255 |
if container.Config.StdinOnce && !container.Config.Tty {
|
| 256 | 256 |
defer cStdin.Close() |
| 257 | 257 |
} |
| 258 |
- _, err := io.Copy(cStdin, stdin) |
|
| 258 |
+ if container.Config.Tty {
|
|
| 259 |
+ _, err = CopyEscapable(cStdin, stdin) |
|
| 260 |
+ } else {
|
|
| 261 |
+ _, err = io.Copy(cStdin, stdin) |
|
| 262 |
+ } |
|
| 259 | 263 |
if err != nil {
|
| 260 | 264 |
Debugf("[error] attach stdin: %s\n", err)
|
| 261 | 265 |
} |
| ... | ... |
@@ -15,7 +15,8 @@ void MakeRaw(int fd) {
|
| 15 | 15 |
ioctl(fd, TCGETS, &t); |
| 16 | 16 |
|
| 17 | 17 |
t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); |
| 18 |
- t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); |
|
| 18 |
+ t.c_oflag &= ~OPOST; |
|
| 19 |
+ t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); |
|
| 19 | 20 |
t.c_cflag &= ~(CSIZE | PARENB); |
| 20 | 21 |
t.c_cflag |= CS8; |
| 21 | 22 |
|
| ... | ... |
@@ -341,3 +341,46 @@ func TruncateId(id string) string {
|
| 341 | 341 |
} |
| 342 | 342 |
return id[:shortLen] |
| 343 | 343 |
} |
| 344 |
+ |
|
| 345 |
+// Code c/c from io.Copy() modified to handle escape sequence |
|
| 346 |
+func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
|
|
| 347 |
+ buf := make([]byte, 32*1024) |
|
| 348 |
+ for {
|
|
| 349 |
+ nr, er := src.Read(buf) |
|
| 350 |
+ if nr > 0 {
|
|
| 351 |
+ // ---- Docker addition |
|
| 352 |
+ // char 16 is C-p |
|
| 353 |
+ if nr == 1 && buf[0] == 16 {
|
|
| 354 |
+ nr, er = src.Read(buf) |
|
| 355 |
+ // char 17 is C-q |
|
| 356 |
+ if nr == 1 && buf[0] == 17 {
|
|
| 357 |
+ if err := src.Close(); err != nil {
|
|
| 358 |
+ return 0, err |
|
| 359 |
+ } |
|
| 360 |
+ return 0, io.EOF |
|
| 361 |
+ } |
|
| 362 |
+ } |
|
| 363 |
+ // ---- End of docker |
|
| 364 |
+ nw, ew := dst.Write(buf[0:nr]) |
|
| 365 |
+ if nw > 0 {
|
|
| 366 |
+ written += int64(nw) |
|
| 367 |
+ } |
|
| 368 |
+ if ew != nil {
|
|
| 369 |
+ err = ew |
|
| 370 |
+ break |
|
| 371 |
+ } |
|
| 372 |
+ if nr != nw {
|
|
| 373 |
+ err = io.ErrShortWrite |
|
| 374 |
+ break |
|
| 375 |
+ } |
|
| 376 |
+ } |
|
| 377 |
+ if er == io.EOF {
|
|
| 378 |
+ break |
|
| 379 |
+ } |
|
| 380 |
+ if er != nil {
|
|
| 381 |
+ err = er |
|
| 382 |
+ break |
|
| 383 |
+ } |
|
| 384 |
+ } |
|
| 385 |
+ return written, err |
|
| 386 |
+} |