github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/cio/io_unix.go (about) 1 // +build !windows 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package cio 20 21 import ( 22 "context" 23 "io" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "sync" 28 "syscall" 29 30 "github.com/containerd/fifo" 31 "github.com/pkg/errors" 32 ) 33 34 // NewFIFOSetInDir returns a new FIFOSet with paths in a temporary directory under root 35 func NewFIFOSetInDir(root, id string, terminal bool) (*FIFOSet, error) { 36 if root != "" { 37 if err := os.MkdirAll(root, 0700); err != nil { 38 return nil, err 39 } 40 } 41 dir, err := ioutil.TempDir(root, "") 42 if err != nil { 43 return nil, err 44 } 45 closer := func() error { 46 return os.RemoveAll(dir) 47 } 48 return NewFIFOSet(Config{ 49 Stdin: filepath.Join(dir, id+"-stdin"), 50 Stdout: filepath.Join(dir, id+"-stdout"), 51 Stderr: filepath.Join(dir, id+"-stderr"), 52 Terminal: terminal, 53 }, closer), nil 54 } 55 56 func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) { 57 var ctx, cancel = context.WithCancel(context.Background()) 58 pipes, err := openFifos(ctx, fifos) 59 if err != nil { 60 cancel() 61 return nil, err 62 } 63 64 if fifos.Stdin != "" { 65 go func() { 66 p := bufPool.Get().(*[]byte) 67 defer bufPool.Put(p) 68 69 io.CopyBuffer(pipes.Stdin, ioset.Stdin, *p) 70 pipes.Stdin.Close() 71 }() 72 } 73 74 var wg = &sync.WaitGroup{} 75 if fifos.Stdout != "" { 76 wg.Add(1) 77 go func() { 78 p := bufPool.Get().(*[]byte) 79 defer bufPool.Put(p) 80 81 io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p) 82 pipes.Stdout.Close() 83 wg.Done() 84 }() 85 } 86 87 if !fifos.Terminal && fifos.Stderr != "" { 88 wg.Add(1) 89 go func() { 90 p := bufPool.Get().(*[]byte) 91 defer bufPool.Put(p) 92 93 io.CopyBuffer(ioset.Stderr, pipes.Stderr, *p) 94 pipes.Stderr.Close() 95 wg.Done() 96 }() 97 } 98 return &cio{ 99 config: fifos.Config, 100 wg: wg, 101 closers: append(pipes.closers(), fifos), 102 cancel: cancel, 103 }, nil 104 } 105 106 func openFifos(ctx context.Context, fifos *FIFOSet) (pipes, error) { 107 var err error 108 defer func() { 109 if err != nil { 110 fifos.Close() 111 } 112 }() 113 114 var f pipes 115 if fifos.Stdin != "" { 116 if f.Stdin, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { 117 return f, errors.Wrapf(err, "failed to open stdin fifo") 118 } 119 defer func() { 120 if err != nil && f.Stdin != nil { 121 f.Stdin.Close() 122 } 123 }() 124 } 125 if fifos.Stdout != "" { 126 if f.Stdout, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { 127 return f, errors.Wrapf(err, "failed to open stdout fifo") 128 } 129 defer func() { 130 if err != nil && f.Stdout != nil { 131 f.Stdout.Close() 132 } 133 }() 134 } 135 if !fifos.Terminal && fifos.Stderr != "" { 136 if f.Stderr, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { 137 return f, errors.Wrapf(err, "failed to open stderr fifo") 138 } 139 } 140 return f, nil 141 } 142 143 // NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser 144 // and io.WriteCloser. 145 func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) { 146 ctx, cancel := context.WithCancel(ctx) 147 pipes, err := openFifos(ctx, fifos) 148 return &DirectIO{ 149 pipes: pipes, 150 cio: cio{ 151 config: fifos.Config, 152 closers: append(pipes.closers(), fifos), 153 cancel: cancel, 154 }, 155 }, err 156 }