@@ -27,8 +27,10 @@ import (
2727 "os/exec"
2828 "path/filepath"
2929 "sync"
30+ "sync/atomic"
3031 "syscall"
3132
33+ "github.com/containerd/containerd/log"
3234 "github.com/containerd/containerd/namespaces"
3335 "github.com/containerd/containerd/runtime/proc"
3436 "github.com/containerd/fifo"
@@ -122,7 +124,7 @@ func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio proc.Stdio
122124}
123125
124126func copyPipes (ctx context.Context , rio runc.IO , stdin , stdout , stderr string , wg , cwg * sync.WaitGroup ) error {
125- var sameFile io. WriteCloser
127+ var sameFile * countingWriteCloser
126128 for _ , i := range []struct {
127129 name string
128130 dest func (wc io.WriteCloser , rc io.Closer )
@@ -136,7 +138,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
136138 cwg .Done ()
137139 p := bufPool .Get ().(* []byte )
138140 defer bufPool .Put (p )
139- io .CopyBuffer (wc , rio .Stdout (), * p )
141+ if _ , err := io .CopyBuffer (wc , rio .Stdout (), * p ); err != nil {
142+ log .G (ctx ).Warn ("error copying stdout" )
143+ }
140144 wg .Done ()
141145 wc .Close ()
142146 if rc != nil {
@@ -153,7 +157,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
153157 cwg .Done ()
154158 p := bufPool .Get ().(* []byte )
155159 defer bufPool .Put (p )
156- io .CopyBuffer (wc , rio .Stderr (), * p )
160+ if _ , err := io .CopyBuffer (wc , rio .Stderr (), * p ); err != nil {
161+ log .G (ctx ).Warn ("error copying stderr" )
162+ }
157163 wg .Done ()
158164 wc .Close ()
159165 if rc != nil {
@@ -180,14 +186,18 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
180186 }
181187 } else {
182188 if sameFile != nil {
189+ sameFile .count ++
183190 i .dest (sameFile , nil )
184191 continue
185192 }
186193 if fw , err = os .OpenFile (i .name , syscall .O_WRONLY | syscall .O_APPEND , 0 ); err != nil {
187194 return fmt .Errorf ("containerd-shim: opening %s failed: %s" , i .name , err )
188195 }
189196 if stdout == stderr {
190- sameFile = fw
197+ sameFile = & countingWriteCloser {
198+ WriteCloser : fw ,
199+ count : 1 ,
200+ }
191201 }
192202 }
193203 i .dest (fw , fr )
@@ -212,6 +222,19 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
212222 return nil
213223}
214224
225+ // countingWriteCloser masks io.Closer() until close has been invoked a certain number of times.
226+ type countingWriteCloser struct {
227+ io.WriteCloser
228+ count int64
229+ }
230+
231+ func (c * countingWriteCloser ) Close () error {
232+ if atomic .AddInt64 (& c .count , - 1 ) > 0 {
233+ return nil
234+ }
235+ return c .WriteCloser .Close ()
236+ }
237+
215238// isFifo checks if a file is a fifo
216239// if the file does not exist then it returns false
217240func isFifo (path string ) (bool , error ) {
0 commit comments