github.com/boynux/docker@v1.11.0-rc4/api/client/attach.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "io" 6 7 "golang.org/x/net/context" 8 9 "github.com/Sirupsen/logrus" 10 Cli "github.com/docker/docker/cli" 11 flag "github.com/docker/docker/pkg/mflag" 12 "github.com/docker/docker/pkg/signal" 13 "github.com/docker/engine-api/types" 14 ) 15 16 // CmdAttach attaches to a running container. 17 // 18 // Usage: docker attach [OPTIONS] CONTAINER 19 func (cli *DockerCli) CmdAttach(args ...string) error { 20 cmd := Cli.Subcmd("attach", []string{"CONTAINER"}, Cli.DockerCommands["attach"].Description, true) 21 noStdin := cmd.Bool([]string{"-no-stdin"}, false, "Do not attach STDIN") 22 proxy := cmd.Bool([]string{"-sig-proxy"}, true, "Proxy all received signals to the process") 23 detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container") 24 25 cmd.Require(flag.Exact, 1) 26 27 cmd.ParseFlags(args, true) 28 29 c, err := cli.client.ContainerInspect(context.Background(), cmd.Arg(0)) 30 if err != nil { 31 return err 32 } 33 34 if !c.State.Running { 35 return fmt.Errorf("You cannot attach to a stopped container, start it first") 36 } 37 38 if c.State.Paused { 39 return fmt.Errorf("You cannot attach to a paused container, unpause it first") 40 } 41 42 if err := cli.CheckTtyInput(!*noStdin, c.Config.Tty); err != nil { 43 return err 44 } 45 46 if *detachKeys != "" { 47 cli.configFile.DetachKeys = *detachKeys 48 } 49 50 options := types.ContainerAttachOptions{ 51 ContainerID: cmd.Arg(0), 52 Stream: true, 53 Stdin: !*noStdin && c.Config.OpenStdin, 54 Stdout: true, 55 Stderr: true, 56 DetachKeys: cli.configFile.DetachKeys, 57 } 58 59 var in io.ReadCloser 60 if options.Stdin { 61 in = cli.in 62 } 63 64 if *proxy && !c.Config.Tty { 65 sigc := cli.forwardAllSignals(options.ContainerID) 66 defer signal.StopCatch(sigc) 67 } 68 69 resp, err := cli.client.ContainerAttach(context.Background(), options) 70 if err != nil { 71 return err 72 } 73 defer resp.Close() 74 if in != nil && c.Config.Tty { 75 if err := cli.setRawTerminal(); err != nil { 76 return err 77 } 78 defer cli.restoreTerminal(in) 79 } 80 81 if c.Config.Tty && cli.isTerminalOut { 82 height, width := cli.getTtySize() 83 // To handle the case where a user repeatedly attaches/detaches without resizing their 84 // terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially 85 // resize it, then go back to normal. Without this, every attach after the first will 86 // require the user to manually resize or hit enter. 87 cli.resizeTtyTo(cmd.Arg(0), height+1, width+1, false) 88 89 // After the above resizing occurs, the call to monitorTtySize below will handle resetting back 90 // to the actual size. 91 if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil { 92 logrus.Debugf("Error monitoring TTY size: %s", err) 93 } 94 } 95 96 if err := cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp); err != nil { 97 return err 98 } 99 100 _, status, err := getExitCode(cli, options.ContainerID) 101 if err != nil { 102 return err 103 } 104 if status != 0 { 105 return Cli.StatusError{StatusCode: status} 106 } 107 108 return nil 109 }