tty.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // +build linux
  2. package runc
  3. import (
  4. "fmt"
  5. "io"
  6. "os"
  7. "sync"
  8. "github.com/docker/docker/pkg/term"
  9. "github.com/opencontainers/runc/libcontainer"
  10. )
  11. // setup standard pipes so that the TTY of the calling runc process
  12. // is not inherited by the container.
  13. func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) {
  14. i, err := p.InitializeIO(rootuid)
  15. if err != nil {
  16. return nil, err
  17. }
  18. t := &tty{
  19. closers: []io.Closer{
  20. i.Stdin,
  21. i.Stdout,
  22. i.Stderr,
  23. },
  24. }
  25. // add the process's io to the post start closers if they support close
  26. for _, cc := range []interface{}{
  27. p.Stdin,
  28. p.Stdout,
  29. p.Stderr,
  30. } {
  31. if c, ok := cc.(io.Closer); ok {
  32. t.postStart = append(t.postStart, c)
  33. }
  34. }
  35. go func() {
  36. io.Copy(i.Stdin, os.Stdin)
  37. i.Stdin.Close()
  38. }()
  39. t.wg.Add(2)
  40. go t.copyIO(os.Stdout, i.Stdout)
  41. go t.copyIO(os.Stderr, i.Stderr)
  42. return t, nil
  43. }
  44. func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
  45. defer t.wg.Done()
  46. io.Copy(w, r)
  47. r.Close()
  48. }
  49. func createTty(p *libcontainer.Process, rootuid int, consolePath string) (*tty, error) {
  50. if consolePath != "" {
  51. if err := p.ConsoleFromPath(consolePath); err != nil {
  52. return nil, err
  53. }
  54. return &tty{}, nil
  55. }
  56. console, err := p.NewConsole(rootuid)
  57. if err != nil {
  58. return nil, err
  59. }
  60. go io.Copy(console, os.Stdin)
  61. go io.Copy(os.Stdout, console)
  62. state, err := term.SetRawTerminal(os.Stdin.Fd())
  63. if err != nil {
  64. return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err)
  65. }
  66. return &tty{
  67. console: console,
  68. state: state,
  69. closers: []io.Closer{
  70. console,
  71. },
  72. }, nil
  73. }
  74. type tty struct {
  75. console libcontainer.Console
  76. state *term.State
  77. closers []io.Closer
  78. postStart []io.Closer
  79. wg sync.WaitGroup
  80. }
  81. // ClosePostStart closes any fds that are provided to the container and dup2'd
  82. // so that we no longer have copy in our process.
  83. func (t *tty) ClosePostStart() error {
  84. for _, c := range t.postStart {
  85. c.Close()
  86. }
  87. return nil
  88. }
  89. // Close closes all open fds for the tty and/or restores the orignal
  90. // stdin state to what it was prior to the container execution
  91. func (t *tty) Close() error {
  92. // ensure that our side of the fds are always closed
  93. for _, c := range t.postStart {
  94. c.Close()
  95. }
  96. // wait for the copy routines to finish before closing the fds
  97. t.wg.Wait()
  98. for _, c := range t.closers {
  99. c.Close()
  100. }
  101. if t.state != nil {
  102. term.RestoreTerminal(os.Stdin.Fd(), t.state)
  103. }
  104. return nil
  105. }
  106. func (t *tty) resize() error {
  107. if t.console == nil {
  108. return nil
  109. }
  110. ws, err := term.GetWinsize(os.Stdin.Fd())
  111. if err != nil {
  112. return err
  113. }
  114. return term.SetWinsize(t.console.Fd(), ws)
  115. }