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