func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) { if err := os.MkdirAll(p.dir, 0700); err != nil { return nil, err } ctx, _ := context.WithTimeout(context.Background(), 15*time.Second) io := &IOPipe{} io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdin), unix.O_WRONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stdin.Close() } }() io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdout), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stdout.Close() } }() if goruntime.GOOS == "solaris" || !terminal { // For Solaris terminal handling is done exclusively by the runtime therefore we make no distinction // in the processing for terminal and !terminal cases. io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(unix.Stderr), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stderr.Close() } }() } else { io.Stderr = ioutil.NopCloser(emptyReader{}) } return io, nil }
func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) { if err := os.MkdirAll(p.dir, 0700); err != nil { return nil, err } ctx, _ := context.WithTimeout(context.Background(), 15*time.Second) io := &IOPipe{} io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stdin), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stdin.Close() } }() io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stdout), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stdout.Close() } }() if !terminal { io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stderr), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) if err != nil { return nil, err } defer func() { if err != nil { io.Stderr.Close() } }() } else { io.Stderr = ioutil.NopCloser(emptyReader{}) } return io, nil }
func prepareStdio(in, out, err string) (*sync.WaitGroup, error) { var ( wg sync.WaitGroup dst io.Writer src io.Reader close func() ) for _, f := range []struct { name string flags int src bool reader io.Reader writer io.Writer }{ {in, syscall.O_WRONLY | syscall.O_CREAT | syscall.O_NONBLOCK, false, os.Stdin, nil}, {out, syscall.O_RDONLY | syscall.O_CREAT | syscall.O_NONBLOCK, true, nil, os.Stdout}, {err, syscall.O_RDONLY | syscall.O_CREAT | syscall.O_NONBLOCK, true, nil, os.Stderr}, } { ff, err := fifo.OpenFifo(gocontext.Background(), f.name, f.flags, 0700) if err != nil { return nil, err } defer func(c io.Closer) { if err != nil { c.Close() } }(ff) if f.src { src = ff dst = f.writer close = func() { ff.Close() wg.Done() } wg.Add(1) } else { src = f.reader dst = ff close = func() { ff.Close() } } go func(dst io.Writer, src io.Reader, close func()) { io.Copy(dst, src) close() }(dst, src, close) } return &wg, nil }
// discardFifos attempts to fully read the container fifos to unblock processes // that may be blocked on the writer side. func (ctr *container) discardFifos() { ctx, _ := context.WithTimeout(context.Background(), 3*time.Second) for _, i := range []int{syscall.Stdout, syscall.Stderr} { f, err := fifo.OpenFifo(ctx, ctr.fifo(i), syscall.O_RDONLY|syscall.O_NONBLOCK, 0) if err != nil { logrus.Warnf("error opening fifo %v for discarding: %+v", f, err) continue } go func() { io.Copy(ioutil.Discard, f) }() } }