github.com/akerouanton/docker@v1.11.0-rc3/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  	go func() {
    83  		stdoutf, err := os.OpenFile(fn, syscall.O_RDONLY, 0)
    84  		if err != nil {
    85  			r.CloseWithError(err)
    86  		}
    87  		if _, err := io.Copy(w, stdoutf); err != nil {
    88  			r.CloseWithError(err)
    89  		}
    90  		w.Close()
    91  		stdoutf.Close()
    92  	}()
    93  	return r
    94  }
    95  
    96  // closeReaderFifo closes fifo that may be blocked on open by opening the write side.
    97  func closeReaderFifo(fn string) {
    98  	f, err := os.OpenFile(fn, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
    99  	if err != nil {
   100  		return
   101  	}
   102  	f.Close()
   103  }
   104  
   105  func (p *process) fifo(index int) string {
   106  	return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
   107  }