tty.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package container
  2. import (
  3. "fmt"
  4. "os"
  5. gosignal "os/signal"
  6. "runtime"
  7. "time"
  8. "github.com/Sirupsen/logrus"
  9. "github.com/docker/docker/api/types"
  10. "github.com/docker/docker/cli/command"
  11. "github.com/docker/docker/client"
  12. "github.com/docker/docker/pkg/signal"
  13. "golang.org/x/net/context"
  14. )
  15. // resizeTtyTo resizes tty to specific height and width
  16. func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) {
  17. if height == 0 && width == 0 {
  18. return
  19. }
  20. options := types.ResizeOptions{
  21. Height: height,
  22. Width: width,
  23. }
  24. var err error
  25. if isExec {
  26. err = client.ContainerExecResize(ctx, id, options)
  27. } else {
  28. err = client.ContainerResize(ctx, id, options)
  29. }
  30. if err != nil {
  31. logrus.Debugf("Error resize: %s", err)
  32. }
  33. }
  34. // MonitorTtySize updates the container tty size when the terminal tty changes size
  35. func MonitorTtySize(ctx context.Context, cli *command.DockerCli, id string, isExec bool) error {
  36. resizeTty := func() {
  37. height, width := cli.Out().GetTtySize()
  38. resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
  39. }
  40. resizeTty()
  41. if runtime.GOOS == "windows" {
  42. go func() {
  43. prevH, prevW := cli.Out().GetTtySize()
  44. for {
  45. time.Sleep(time.Millisecond * 250)
  46. h, w := cli.Out().GetTtySize()
  47. if prevW != w || prevH != h {
  48. resizeTty()
  49. }
  50. prevH = h
  51. prevW = w
  52. }
  53. }()
  54. } else {
  55. sigchan := make(chan os.Signal, 1)
  56. gosignal.Notify(sigchan, signal.SIGWINCH)
  57. go func() {
  58. for range sigchan {
  59. resizeTty()
  60. }
  61. }()
  62. }
  63. return nil
  64. }
  65. // ForwardAllSignals forwards signals to the container
  66. func ForwardAllSignals(ctx context.Context, cli *command.DockerCli, cid string) chan os.Signal {
  67. sigc := make(chan os.Signal, 128)
  68. signal.CatchAll(sigc)
  69. go func() {
  70. for s := range sigc {
  71. if s == signal.SIGCHLD || s == signal.SIGPIPE {
  72. continue
  73. }
  74. var sig string
  75. for sigStr, sigN := range signal.SignalMap {
  76. if sigN == s {
  77. sig = sigStr
  78. break
  79. }
  80. }
  81. if sig == "" {
  82. fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s)
  83. continue
  84. }
  85. if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
  86. logrus.Debugf("Error sending signal: %s", err)
  87. }
  88. }
  89. }()
  90. return sigc
  91. }