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