Cleanup binary IO resources on error
@@ -246,11 +246,12 @@ func (c *countingWriteCloser) Close() error {
}
// NewBinaryIO runs a custom binary process for pluggable shim logging
-func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error) {
+func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (_ runc.IO, err error) {
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
}
+
var args []string
for k, vs := range uri.Query() {
args = append(args, k)
@@ -259,20 +260,35 @@ func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error)
}
}
+ var closers []func() error
+ defer func() {
+ if err == nil {
+ return
+ }
+ result := multierror.Append(err)
+ for _, fn := range closers {
+ result = multierror.Append(result, fn())
+ }
+ err = multierror.Flatten(result)
+ }()
+
out, err := newPipe()
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "failed to create stdout pipes")
}
+ closers = append(closers, out.Close)
serr, err := newPipe()
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "failed to create stderr pipes")
}
+ closers = append(closers, serr.Close)
r, w, err := os.Pipe()
if err != nil {
return nil, err
}
+ closers = append(closers, r.Close, w.Close)
cmd := exec.Command(uri.Path, args...)
cmd.Env = append(cmd.Env,
@@ -284,17 +300,21 @@ func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error)
// don't need to register this with the reaper or wait when
// running inside a shim
if err := cmd.Start(); err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "failed to start binary process")
}
+ closers = append(closers, func() error { return cmd.Process.Kill() })
+
// close our side of the pipe after start
if err := w.Close(); err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "failed to close write pipe after start")
}
+
// wait for the logging binary to be ready
b := make([]byte, 1)
if _, err := r.Read(b); err != nil && err != io.EOF {
- return nil, err
+ return nil, errors.Wrap(err, "failed to read from logging binary")
}
+
return &binaryIO{
cmd: cmd,
out: out,
@@ -423,9 +443,15 @@ type pipe struct {
}
func (p *pipe) Close() error {
- err := p.w.Close()
- if rerr := p.r.Close(); err == nil {
- err = rerr
+ var result *multierror.Error
+
+ if err := p.w.Close(); err != nil {
+ result = multierror.Append(result, errors.Wrap(err, "failed to close write pipe"))
}
- return err
+
+ if err := p.r.Close(); err != nil {
+ result = multierror.Append(result, errors.Wrap(err, "failed to close read pipe"))
+ }
+
+ return multierror.Prefix(result.ErrorOrNil(), "pipe:")
}
