in.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package client
  2. import (
  3. "errors"
  4. "io"
  5. "os"
  6. "runtime"
  7. "github.com/docker/docker/pkg/term"
  8. )
  9. // InStream is an input stream used by the DockerCli to read user input
  10. type InStream struct {
  11. in io.ReadCloser
  12. fd uintptr
  13. isTerminal bool
  14. state *term.State
  15. }
  16. func (i *InStream) Read(p []byte) (int, error) {
  17. return i.in.Read(p)
  18. }
  19. // Close implements the Closer interface
  20. func (i *InStream) Close() error {
  21. return i.in.Close()
  22. }
  23. // FD returns the file descriptor number for this stream
  24. func (i *InStream) FD() uintptr {
  25. return i.fd
  26. }
  27. // IsTerminal returns true if this stream is connected to a terminal
  28. func (i *InStream) IsTerminal() bool {
  29. return i.isTerminal
  30. }
  31. func (i *InStream) setRawTerminal() (err error) {
  32. if os.Getenv("NORAW") != "" || !i.isTerminal {
  33. return nil
  34. }
  35. i.state, err = term.SetRawTerminal(i.fd)
  36. return err
  37. }
  38. func (i *InStream) restoreTerminal() {
  39. if i.state != nil {
  40. term.RestoreTerminal(i.fd, i.state)
  41. }
  42. }
  43. // CheckTty checks if we are trying to attach to a container tty
  44. // from a non-tty client input stream, and if so, returns an error.
  45. func (i *InStream) CheckTty(attachStdin, ttyMode bool) error {
  46. // In order to attach to a container tty, input stream for the client must
  47. // be a tty itself: redirecting or piping the client standard input is
  48. // incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
  49. if ttyMode && attachStdin && !i.isTerminal {
  50. eText := "the input device is not a TTY"
  51. if runtime.GOOS == "windows" {
  52. return errors.New(eText + ". If you are using mintty, try prefixing the command with 'winpty'")
  53. }
  54. return errors.New(eText)
  55. }
  56. return nil
  57. }
  58. // NewInStream returns a new OutStream object from a Writer
  59. func NewInStream(in io.ReadCloser) *InStream {
  60. fd, isTerminal := term.GetFdInfo(in)
  61. return &InStream{in: in, fd: fd, isTerminal: isTerminal}
  62. }