mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
e918d02139
This removes libcontainer's own error wrapping system, consisting of a few types and functions, aimed at typization, wrapping and unwrapping of errors, as well as saving error stack traces. Since Go 1.13 now provides its own error wrapping mechanism and a few related functions, it makes sense to switch to it. While doing that, improve some error messages so that they start with "error", "unable to", or "can't". A few things that are worth mentioning: 1. We lose stack traces (which were never shown anyway). 2. Users of libcontainer that relied on particular errors (like ContainerNotExists) need to switch to using errors.Is with the new errors defined in error.go. 3. encoding/json is unable to unmarshal the built-in error type, so we have to introduce initError and wrap the errors into it (basically passing the error as a string). This is the same as it was before, just a tad simpler (actually the initError is a type that got removed in commit afa844311; also suddenly ierr variable name makes sense now). Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
package libcontainer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/utils"
|
|
)
|
|
|
|
type syncType string
|
|
|
|
// Constants that are used for synchronisation between the parent and child
|
|
// during container setup. They come in pairs (with procError being a generic
|
|
// response which is followed by an &initError).
|
|
//
|
|
// [ child ] <-> [ parent ]
|
|
//
|
|
// procHooks --> [run hooks]
|
|
// <-- procResume
|
|
//
|
|
// procReady --> [final setup]
|
|
// <-- procRun
|
|
const (
|
|
procError syncType = "procError"
|
|
procReady syncType = "procReady"
|
|
procRun syncType = "procRun"
|
|
procHooks syncType = "procHooks"
|
|
procResume syncType = "procResume"
|
|
)
|
|
|
|
type syncT struct {
|
|
Type syncType `json:"type"`
|
|
}
|
|
|
|
// initError is used to wrap errors for passing them via JSON,
|
|
// as encoding/json can't unmarshal into error type.
|
|
type initError struct {
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
func (i initError) Error() string {
|
|
return i.Message
|
|
}
|
|
|
|
// writeSync is used to write to a synchronisation pipe. An error is returned
|
|
// if there was a problem writing the payload.
|
|
func writeSync(pipe io.Writer, sync syncType) error {
|
|
return utils.WriteJSON(pipe, syncT{sync})
|
|
}
|
|
|
|
// readSync is used to read from a synchronisation pipe. An error is returned
|
|
// if we got an initError, the pipe was closed, or we got an unexpected flag.
|
|
func readSync(pipe io.Reader, expected syncType) error {
|
|
var procSync syncT
|
|
if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
return errors.New("parent closed synchronisation channel")
|
|
}
|
|
return fmt.Errorf("failed reading error from parent: %w", err)
|
|
}
|
|
|
|
if procSync.Type == procError {
|
|
var ierr initError
|
|
|
|
if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
|
|
return fmt.Errorf("failed reading error from parent: %w", err)
|
|
}
|
|
|
|
return &ierr
|
|
}
|
|
|
|
if procSync.Type != expected {
|
|
return errors.New("invalid synchronisation flag from parent")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// parseSync runs the given callback function on each syncT received from the
|
|
// child. It will return once io.EOF is returned from the given pipe.
|
|
func parseSync(pipe io.Reader, fn func(*syncT) error) error {
|
|
dec := json.NewDecoder(pipe)
|
|
for {
|
|
var sync syncT
|
|
if err := dec.Decode(&sync); err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
return err
|
|
}
|
|
|
|
// We handle this case outside fn for cleanliness reasons.
|
|
var ierr *initError
|
|
if sync.Type == procError {
|
|
if err := dec.Decode(&ierr); err != nil && !errors.Is(err, io.EOF) {
|
|
return fmt.Errorf("error decoding proc error from init: %w", err)
|
|
}
|
|
if ierr != nil {
|
|
return ierr
|
|
}
|
|
// Programmer error.
|
|
panic("No error following JSON procError payload.")
|
|
}
|
|
|
|
if err := fn(&sync); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|