process_linux.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package libcontainerd
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. "syscall"
  8. containerd "github.com/docker/containerd/api/grpc/types"
  9. "github.com/docker/docker/pkg/ioutils"
  10. "golang.org/x/net/context"
  11. )
  12. var fdNames = map[int]string{
  13. syscall.Stdin: "stdin",
  14. syscall.Stdout: "stdout",
  15. syscall.Stderr: "stderr",
  16. }
  17. // process keeps the state for both main container process and exec process.
  18. type process struct {
  19. processCommon
  20. // Platform specific fields are below here.
  21. dir string
  22. }
  23. func (p *process) openFifos(terminal bool) (*IOPipe, error) {
  24. bundleDir := p.dir
  25. if err := os.MkdirAll(bundleDir, 0700); err != nil {
  26. return nil, err
  27. }
  28. for i := 0; i < 3; i++ {
  29. f := p.fifo(i)
  30. if err := syscall.Mkfifo(f, 0700); err != nil && !os.IsExist(err) {
  31. return nil, fmt.Errorf("mkfifo: %s %v", f, err)
  32. }
  33. }
  34. io := &IOPipe{}
  35. stdinf, err := os.OpenFile(p.fifo(syscall.Stdin), syscall.O_RDWR, 0)
  36. if err != nil {
  37. return nil, err
  38. }
  39. io.Stdout = openReaderFromFifo(p.fifo(syscall.Stdout))
  40. if !terminal {
  41. io.Stderr = openReaderFromFifo(p.fifo(syscall.Stderr))
  42. } else {
  43. io.Stderr = emptyReader{}
  44. }
  45. io.Stdin = ioutils.NewWriteCloserWrapper(stdinf, func() error {
  46. stdinf.Close()
  47. _, err := p.client.remote.apiClient.UpdateProcess(context.Background(), &containerd.UpdateProcessRequest{
  48. Id: p.containerID,
  49. Pid: p.friendlyName,
  50. CloseStdin: true,
  51. })
  52. return err
  53. })
  54. return io, nil
  55. }
  56. func (p *process) closeFifos(io *IOPipe) {
  57. io.Stdin.Close()
  58. closeReaderFifo(p.fifo(syscall.Stdout))
  59. closeReaderFifo(p.fifo(syscall.Stderr))
  60. }
  61. type emptyReader struct{}
  62. func (r emptyReader) Read(b []byte) (int, error) {
  63. return 0, io.EOF
  64. }
  65. func openReaderFromFifo(fn string) io.Reader {
  66. r, w := io.Pipe()
  67. c := make(chan struct{})
  68. go func() {
  69. close(c)
  70. stdoutf, err := os.OpenFile(fn, syscall.O_RDONLY, 0)
  71. if err != nil {
  72. r.CloseWithError(err)
  73. }
  74. if _, err := io.Copy(w, stdoutf); err != nil {
  75. r.CloseWithError(err)
  76. }
  77. w.Close()
  78. stdoutf.Close()
  79. }()
  80. <-c // wait for the goroutine to get scheduled and syscall to block
  81. return r
  82. }
  83. // closeReaderFifo closes fifo that may be blocked on open by opening the write side.
  84. func closeReaderFifo(fn string) {
  85. f, err := os.OpenFile(fn, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
  86. if err != nil {
  87. return
  88. }
  89. f.Close()
  90. }
  91. func (p *process) fifo(index int) string {
  92. return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
  93. }