io.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. Copyright The containerd Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package runc
  14. import (
  15. "io"
  16. "os"
  17. "os/exec"
  18. )
  19. // IO is the terminal IO interface
  20. type IO interface {
  21. io.Closer
  22. Stdin() io.WriteCloser
  23. Stdout() io.ReadCloser
  24. Stderr() io.ReadCloser
  25. Set(*exec.Cmd)
  26. }
  27. // StartCloser is an interface to handle IO closure after start
  28. type StartCloser interface {
  29. CloseAfterStart() error
  30. }
  31. // IOOpt sets I/O creation options
  32. type IOOpt func(*IOOption)
  33. // IOOption holds I/O creation options
  34. type IOOption struct {
  35. OpenStdin bool
  36. OpenStdout bool
  37. OpenStderr bool
  38. }
  39. func defaultIOOption() *IOOption {
  40. return &IOOption{
  41. OpenStdin: true,
  42. OpenStdout: true,
  43. OpenStderr: true,
  44. }
  45. }
  46. func newPipe() (*pipe, error) {
  47. r, w, err := os.Pipe()
  48. if err != nil {
  49. return nil, err
  50. }
  51. return &pipe{
  52. r: r,
  53. w: w,
  54. }, nil
  55. }
  56. type pipe struct {
  57. r *os.File
  58. w *os.File
  59. }
  60. func (p *pipe) Close() error {
  61. err := p.w.Close()
  62. if rerr := p.r.Close(); err == nil {
  63. err = rerr
  64. }
  65. return err
  66. }
  67. // NewPipeIO creates pipe pairs to be used with runc. It is not implemented
  68. // on Windows.
  69. func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) {
  70. return newPipeIO(uid, gid, opts...)
  71. }
  72. type pipeIO struct {
  73. in *pipe
  74. out *pipe
  75. err *pipe
  76. }
  77. func (i *pipeIO) Stdin() io.WriteCloser {
  78. if i.in == nil {
  79. return nil
  80. }
  81. return i.in.w
  82. }
  83. func (i *pipeIO) Stdout() io.ReadCloser {
  84. if i.out == nil {
  85. return nil
  86. }
  87. return i.out.r
  88. }
  89. func (i *pipeIO) Stderr() io.ReadCloser {
  90. if i.err == nil {
  91. return nil
  92. }
  93. return i.err.r
  94. }
  95. func (i *pipeIO) Close() error {
  96. var err error
  97. for _, v := range []*pipe{
  98. i.in,
  99. i.out,
  100. i.err,
  101. } {
  102. if v != nil {
  103. if cerr := v.Close(); err == nil {
  104. err = cerr
  105. }
  106. }
  107. }
  108. return err
  109. }
  110. func (i *pipeIO) CloseAfterStart() error {
  111. for _, f := range []*pipe{
  112. i.out,
  113. i.err,
  114. } {
  115. if f != nil {
  116. f.w.Close()
  117. }
  118. }
  119. return nil
  120. }
  121. // Set sets the io to the exec.Cmd
  122. func (i *pipeIO) Set(cmd *exec.Cmd) {
  123. if i.in != nil {
  124. cmd.Stdin = i.in.r
  125. }
  126. if i.out != nil {
  127. cmd.Stdout = i.out.w
  128. }
  129. if i.err != nil {
  130. cmd.Stderr = i.err.w
  131. }
  132. }
  133. // NewSTDIO returns I/O setup for standard OS in/out/err usage
  134. func NewSTDIO() (IO, error) {
  135. return &stdio{}, nil
  136. }
  137. type stdio struct{}
  138. func (s *stdio) Close() error {
  139. return nil
  140. }
  141. func (s *stdio) Set(cmd *exec.Cmd) {
  142. cmd.Stdin = os.Stdin
  143. cmd.Stdout = os.Stdout
  144. cmd.Stderr = os.Stderr
  145. }
  146. func (s *stdio) Stdin() io.WriteCloser {
  147. return os.Stdin
  148. }
  149. func (s *stdio) Stdout() io.ReadCloser {
  150. return os.Stdout
  151. }
  152. func (s *stdio) Stderr() io.ReadCloser {
  153. return os.Stderr
  154. }
  155. // NewNullIO returns IO setup for /dev/null use with runc
  156. func NewNullIO() (IO, error) {
  157. f, err := os.Open(os.DevNull)
  158. if err != nil {
  159. return nil, err
  160. }
  161. return &nullIO{
  162. devNull: f,
  163. }, nil
  164. }
  165. type nullIO struct {
  166. devNull *os.File
  167. }
  168. func (n *nullIO) Close() error {
  169. // this should be closed after start but if not
  170. // make sure we close the file but don't return the error
  171. n.devNull.Close()
  172. return nil
  173. }
  174. func (n *nullIO) Stdin() io.WriteCloser {
  175. return nil
  176. }
  177. func (n *nullIO) Stdout() io.ReadCloser {
  178. return nil
  179. }
  180. func (n *nullIO) Stderr() io.ReadCloser {
  181. return nil
  182. }
  183. func (n *nullIO) Set(c *exec.Cmd) {
  184. // don't set STDIN here
  185. c.Stdout = n.devNull
  186. c.Stderr = n.devNull
  187. }
  188. func (n *nullIO) CloseAfterStart() error {
  189. return n.devNull.Close()
  190. }