docker.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package main
  2. import (
  3. "github.com/dotcloud/docker/rcli"
  4. "github.com/dotcloud/docker/future"
  5. "io"
  6. "log"
  7. "os"
  8. "syscall"
  9. "unsafe"
  10. )
  11. type Termios struct {
  12. Iflag uintptr
  13. Oflag uintptr
  14. Cflag uintptr
  15. Lflag uintptr
  16. Cc [20]byte
  17. Ispeed uintptr
  18. Ospeed uintptr
  19. }
  20. const (
  21. // Input flags
  22. inpck = 0x010
  23. istrip = 0x020
  24. icrnl = 0x100
  25. ixon = 0x200
  26. // Output flags
  27. opost = 0x1
  28. // Control flags
  29. cs8 = 0x300
  30. // Local flags
  31. icanon = 0x100
  32. iexten = 0x400
  33. )
  34. const (
  35. HUPCL = 0x4000
  36. ICANON = 0x100
  37. ICRNL = 0x100
  38. IEXTEN = 0x400
  39. BRKINT = 0x2
  40. CFLUSH = 0xf
  41. CLOCAL = 0x8000
  42. CREAD = 0x800
  43. CS5 = 0x0
  44. CS6 = 0x100
  45. CS7 = 0x200
  46. CS8 = 0x300
  47. CSIZE = 0x300
  48. CSTART = 0x11
  49. CSTATUS = 0x14
  50. CSTOP = 0x13
  51. CSTOPB = 0x400
  52. CSUSP = 0x1a
  53. IGNBRK = 0x1
  54. IGNCR = 0x80
  55. IGNPAR = 0x4
  56. IMAXBEL = 0x2000
  57. INLCR = 0x40
  58. INPCK = 0x10
  59. ISIG = 0x80
  60. ISTRIP = 0x20
  61. IUTF8 = 0x4000
  62. IXANY = 0x800
  63. IXOFF = 0x400
  64. IXON = 0x200
  65. NOFLSH = 0x80000000
  66. OCRNL = 0x10
  67. OFDEL = 0x20000
  68. OFILL = 0x80
  69. ONLCR = 0x2
  70. ONLRET = 0x40
  71. ONOCR = 0x20
  72. ONOEOT = 0x8
  73. OPOST = 0x1
  74. RENB = 0x1000
  75. PARMRK = 0x8
  76. PARODD = 0x2000
  77. TOSTOP = 0x400000
  78. VDISCARD = 0xf
  79. VDSUSP = 0xb
  80. VEOF = 0x0
  81. VEOL = 0x1
  82. VEOL2 = 0x2
  83. VERASE = 0x3
  84. VINTR = 0x8
  85. VKILL = 0x5
  86. VLNEXT = 0xe
  87. VMIN = 0x10
  88. VQUIT = 0x9
  89. VREPRINT = 0x6
  90. VSTART = 0xc
  91. VSTATUS = 0x12
  92. VSTOP = 0xd
  93. VSUSP = 0xa
  94. VT0 = 0x0
  95. VT1 = 0x10000
  96. VTDLY = 0x10000
  97. VTIME = 0x11
  98. ECHO = 0x00000008
  99. PENDIN = 0x20000000
  100. )
  101. type State struct {
  102. termios Termios
  103. }
  104. // IsTerminal returns true if the given file descriptor is a terminal.
  105. func IsTerminal(fd int) bool {
  106. var termios Termios
  107. _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
  108. return err == 0
  109. }
  110. // MakeRaw put the terminal connected to the given file descriptor into raw
  111. // mode and returns the previous state of the terminal so that it can be
  112. // restored.
  113. func MakeRaw(fd int) (*State, error) {
  114. var oldState State
  115. if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
  116. return nil, err
  117. }
  118. newState := oldState.termios
  119. newState.Iflag &^= istrip | INLCR | ICRNL | IGNCR | IXON | IXOFF
  120. newState.Lflag &^= ECHO | ICANON | ISIG
  121. if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
  122. return nil, err
  123. }
  124. return &oldState, nil
  125. }
  126. // Restore restores the terminal connected to the given file descriptor to a
  127. // previous state.
  128. func Restore(fd int, state *State) error {
  129. _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
  130. return err
  131. }
  132. var oldState *State
  133. func Fatal(err error) {
  134. if oldState != nil {
  135. Restore(0, oldState)
  136. }
  137. log.Fatal(err)
  138. }
  139. func main() {
  140. var err error
  141. if IsTerminal(0) {
  142. oldState, err = MakeRaw(0)
  143. if err != nil {
  144. panic(err)
  145. }
  146. defer Restore(0, oldState)
  147. }
  148. conn, err := rcli.CallTCP(os.Getenv("DOCKER"), os.Args[1:]...)
  149. if err != nil {
  150. Fatal(err)
  151. }
  152. receive_stdout := future.Go(func() error {
  153. _, err := io.Copy(os.Stdout, conn)
  154. return err
  155. })
  156. send_stdin := future.Go(func() error {
  157. _, err := io.Copy(conn, os.Stdin)
  158. if err := conn.CloseWrite(); err != nil {
  159. log.Printf("Couldn't send EOF: " + err.Error())
  160. }
  161. return err
  162. })
  163. if err := <-receive_stdout; err != nil {
  164. Fatal(err)
  165. }
  166. if IsTerminal(0) {
  167. Restore(0, oldState)
  168. } else {
  169. if err := <-send_stdin; err != nil {
  170. Fatal(err)
  171. }
  172. }
  173. }