diff --git a/Gopkg.lock b/Gopkg.lock index d2e08ef408f500b7bb0d458f11619c73a804173f..90c253ee95c461355b9d19fa91e448fa3248f881 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -523,13 +523,12 @@ version = "v1.0.1" [[projects]] - branch = "gitlab-runner" - digest = "1:75b40fc42638e16795927c70e04245019e3ac57ae1253b8e4b2b9f6e7b9c1842" + branch = "master" + digest = "1:37fa7939ecc94700a86a4658e769e5b298d38685b29c43e8100e10b123971cc4" name = "github.com/opencontainers/runc" packages = ["libcontainer/user"] pruneopts = "N" - revision = "fd48010b807f3c267c19f8f14ca6dca2370d0b54" - source = "github.com/nolith/runc" + revision = "c1e454b2a1bfb0f0ebd9e621a1433f98f9a8d4b0" [[projects]] digest = "1:5da5dc86bcd23e94befc0048ccd757fc1706ebd3aa6c0ca9575d8b9def1b8f26" diff --git a/Gopkg.toml b/Gopkg.toml index e8f82aeb165d47caefa23f2b5e587129107f58b3..a22189a3f39728fa3729b2dcdc70fbb340719da3 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -229,11 +229,9 @@ ignored = ["test", "appengine"] name = "github.com/minio/go-homedir" revision = "4d76aabb80b22bad8695d3904e943f1fb5e6199f" -# temporary fork to hanled Sirupsen -> sirupsen [[override]] name = "github.com/opencontainers/runc" - branch = "gitlab-runner" - source = "github.com/nolith/runc" + branch = "master" [[override]] name = "github.com/opencontainers/runtime-spec" diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE deleted file mode 100644 index f090cb42f370bda9e7f4f58d9b8b8ee2750c115f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Simon Eskildsen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go deleted file mode 100644 index 17fe6f707bca7c5d58a81b8e2e15543960e7a6f5..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go +++ /dev/null @@ -1,252 +0,0 @@ -package logrus - -import ( - "bytes" - "fmt" - "io" - "os" - "time" -) - -// An entry is the final or intermediate Logrus logging entry. It contains all -// the fields passed with WithField{,s}. It's finally logged when Debug, Info, -// Warn, Error, Fatal or Panic is called on it. These objects can be reused and -// passed around as much as you wish to avoid field duplication. -type Entry struct { - Logger *Logger - - // Contains all the fields set by the user. - Data Fields - - // Time at which the log entry was created - Time time.Time - - // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic - Level Level - - // Message passed to Debug, Info, Warn, Error, Fatal or Panic - Message string -} - -func NewEntry(logger *Logger) *Entry { - return &Entry{ - Logger: logger, - // Default is three fields, give a little extra room - Data: make(Fields, 5), - } -} - -// Returns a reader for the entry, which is a proxy to the formatter. -func (entry *Entry) Reader() (*bytes.Buffer, error) { - serialized, err := entry.Logger.Formatter.Format(entry) - return bytes.NewBuffer(serialized), err -} - -// Returns the string representation from the reader and ultimately the -// formatter. -func (entry *Entry) String() (string, error) { - reader, err := entry.Reader() - if err != nil { - return "", err - } - - return reader.String(), err -} - -// Add a single field to the Entry. -func (entry *Entry) WithField(key string, value interface{}) *Entry { - return entry.WithFields(Fields{key: value}) -} - -// Add a map of fields to the Entry. -func (entry *Entry) WithFields(fields Fields) *Entry { - data := Fields{} - for k, v := range entry.Data { - data[k] = v - } - for k, v := range fields { - data[k] = v - } - return &Entry{Logger: entry.Logger, Data: data} -} - -func (entry *Entry) log(level Level, msg string) { - entry.Time = time.Now() - entry.Level = level - entry.Message = msg - - if err := entry.Logger.Hooks.Fire(level, entry); err != nil { - entry.Logger.mu.Lock() - fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) - entry.Logger.mu.Unlock() - } - - reader, err := entry.Reader() - if err != nil { - entry.Logger.mu.Lock() - fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) - entry.Logger.mu.Unlock() - } - - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - - _, err = io.Copy(entry.Logger.Out, reader) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) - } - - // To avoid Entry#log() returning a value that only would make sense for - // panic() to use in Entry#Panic(), we avoid the allocation by checking - // directly here. - if level <= PanicLevel { - panic(entry) - } -} - -func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.Level >= DebugLevel { - entry.log(DebugLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Print(args ...interface{}) { - entry.Info(args...) -} - -func (entry *Entry) Info(args ...interface{}) { - if entry.Logger.Level >= InfoLevel { - entry.log(InfoLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Warn(args ...interface{}) { - if entry.Logger.Level >= WarnLevel { - entry.log(WarnLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Warning(args ...interface{}) { - entry.Warn(args...) -} - -func (entry *Entry) Error(args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { - entry.log(ErrorLevel, fmt.Sprint(args...)) - } -} - -func (entry *Entry) Fatal(args ...interface{}) { - if entry.Logger.Level >= FatalLevel { - entry.log(FatalLevel, fmt.Sprint(args...)) - } - os.Exit(1) -} - -func (entry *Entry) Panic(args ...interface{}) { - if entry.Logger.Level >= PanicLevel { - entry.log(PanicLevel, fmt.Sprint(args...)) - } - panic(fmt.Sprint(args...)) -} - -// Entry Printf family functions - -func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.Level >= DebugLevel { - entry.Debug(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.Logger.Level >= InfoLevel { - entry.Info(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Printf(format string, args ...interface{}) { - entry.Infof(format, args...) -} - -func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.Logger.Level >= WarnLevel { - entry.Warn(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Warningf(format string, args ...interface{}) { - entry.Warnf(format, args...) -} - -func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { - entry.Error(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.Logger.Level >= FatalLevel { - entry.Fatal(fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.Logger.Level >= PanicLevel { - entry.Panic(fmt.Sprintf(format, args...)) - } -} - -// Entry Println family functions - -func (entry *Entry) Debugln(args ...interface{}) { - if entry.Logger.Level >= DebugLevel { - entry.Debug(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Infoln(args ...interface{}) { - if entry.Logger.Level >= InfoLevel { - entry.Info(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Println(args ...interface{}) { - entry.Infoln(args...) -} - -func (entry *Entry) Warnln(args ...interface{}) { - if entry.Logger.Level >= WarnLevel { - entry.Warn(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Warningln(args ...interface{}) { - entry.Warnln(args...) -} - -func (entry *Entry) Errorln(args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { - entry.Error(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Fatalln(args ...interface{}) { - if entry.Logger.Level >= FatalLevel { - entry.Fatal(entry.sprintlnn(args...)) - } -} - -func (entry *Entry) Panicln(args ...interface{}) { - if entry.Logger.Level >= PanicLevel { - entry.Panic(entry.sprintlnn(args...)) - } -} - -// Sprintlnn => Sprint no newline. This is to get the behavior of how -// fmt.Sprintln where spaces are always added between operands, regardless of -// their type. Instead of vendoring the Sprintln implementation to spare a -// string allocation, we do the simplest thing. -func (entry *Entry) sprintlnn(args ...interface{}) string { - msg := fmt.Sprintln(args...) - return msg[:len(msg)-1] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go deleted file mode 100644 index b22468d9c3ee43d96d8dadd9514b0ca4b9b582cd..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "github.com/sirupsen/logrus" -) - -var log = logrus.New() - -func init() { - log.Formatter = new(logrus.JSONFormatter) - log.Formatter = new(logrus.TextFormatter) // default - log.Level = logrus.DebugLevel -} - -func main() { - defer func() { - err := recover() - if err != nil { - log.WithFields(logrus.Fields{ - "omg": true, - "err": err, - "number": 100, - }).Fatal("The ice breaks!") - } - }() - - log.WithFields(logrus.Fields{ - "animal": "walrus", - "number": 8, - }).Debug("Started observing beach") - - log.WithFields(logrus.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") - - log.WithFields(logrus.Fields{ - "omg": true, - "number": 122, - }).Warn("The group's number increased tremendously!") - - log.WithFields(logrus.Fields{ - "temperature": -4, - }).Debug("Temperature changes") - - log.WithFields(logrus.Fields{ - "animal": "orca", - "size": 9009, - }).Panic("It's over 9000!") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go deleted file mode 100644 index 754acc0cf2bc7810bcb9cef4e95d28f7ec08d122..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/airbrake" -) - -var log = logrus.New() - -func init() { - log.Formatter = new(logrus.TextFormatter) // default - log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development")) -} - -func main() { - log.WithFields(logrus.Fields{ - "animal": "walrus", - "size": 10, - }).Info("A group of walrus emerges from the ocean") - - log.WithFields(logrus.Fields{ - "omg": true, - "number": 122, - }).Warn("The group's number increased tremendously!") - - log.WithFields(logrus.Fields{ - "omg": true, - "number": 100, - }).Fatal("The ice breaks!") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go deleted file mode 100644 index a67e1b802d9143be3b804a60776dc6f07163b180..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go +++ /dev/null @@ -1,188 +0,0 @@ -package logrus - -import ( - "io" -) - -var ( - // std is the name of the standard logger in stdlib `log` - std = New() -) - -func StandardLogger() *Logger { - return std -} - -// SetOutput sets the standard logger output. -func SetOutput(out io.Writer) { - std.mu.Lock() - defer std.mu.Unlock() - std.Out = out -} - -// SetFormatter sets the standard logger formatter. -func SetFormatter(formatter Formatter) { - std.mu.Lock() - defer std.mu.Unlock() - std.Formatter = formatter -} - -// SetLevel sets the standard logger level. -func SetLevel(level Level) { - std.mu.Lock() - defer std.mu.Unlock() - std.Level = level -} - -// GetLevel returns the standard logger level. -func GetLevel() Level { - std.mu.Lock() - defer std.mu.Unlock() - return std.Level -} - -// AddHook adds a hook to the standard logger hooks. -func AddHook(hook Hook) { - std.mu.Lock() - defer std.mu.Unlock() - std.Hooks.Add(hook) -} - -// WithField creates an entry from the standard logger and adds a field to -// it. If you want multiple fields, use `WithFields`. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithField(key string, value interface{}) *Entry { - return std.WithField(key, value) -} - -// WithFields creates an entry from the standard logger and adds multiple -// fields to it. This is simply a helper for `WithField`, invoking it -// once for each field. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithFields(fields Fields) *Entry { - return std.WithFields(fields) -} - -// Debug logs a message at level Debug on the standard logger. -func Debug(args ...interface{}) { - std.Debug(args...) -} - -// Print logs a message at level Info on the standard logger. -func Print(args ...interface{}) { - std.Print(args...) -} - -// Info logs a message at level Info on the standard logger. -func Info(args ...interface{}) { - std.Info(args...) -} - -// Warn logs a message at level Warn on the standard logger. -func Warn(args ...interface{}) { - std.Warn(args...) -} - -// Warning logs a message at level Warn on the standard logger. -func Warning(args ...interface{}) { - std.Warning(args...) -} - -// Error logs a message at level Error on the standard logger. -func Error(args ...interface{}) { - std.Error(args...) -} - -// Panic logs a message at level Panic on the standard logger. -func Panic(args ...interface{}) { - std.Panic(args...) -} - -// Fatal logs a message at level Fatal on the standard logger. -func Fatal(args ...interface{}) { - std.Fatal(args...) -} - -// Debugf logs a message at level Debug on the standard logger. -func Debugf(format string, args ...interface{}) { - std.Debugf(format, args...) -} - -// Printf logs a message at level Info on the standard logger. -func Printf(format string, args ...interface{}) { - std.Printf(format, args...) -} - -// Infof logs a message at level Info on the standard logger. -func Infof(format string, args ...interface{}) { - std.Infof(format, args...) -} - -// Warnf logs a message at level Warn on the standard logger. -func Warnf(format string, args ...interface{}) { - std.Warnf(format, args...) -} - -// Warningf logs a message at level Warn on the standard logger. -func Warningf(format string, args ...interface{}) { - std.Warningf(format, args...) -} - -// Errorf logs a message at level Error on the standard logger. -func Errorf(format string, args ...interface{}) { - std.Errorf(format, args...) -} - -// Panicf logs a message at level Panic on the standard logger. -func Panicf(format string, args ...interface{}) { - std.Panicf(format, args...) -} - -// Fatalf logs a message at level Fatal on the standard logger. -func Fatalf(format string, args ...interface{}) { - std.Fatalf(format, args...) -} - -// Debugln logs a message at level Debug on the standard logger. -func Debugln(args ...interface{}) { - std.Debugln(args...) -} - -// Println logs a message at level Info on the standard logger. -func Println(args ...interface{}) { - std.Println(args...) -} - -// Infoln logs a message at level Info on the standard logger. -func Infoln(args ...interface{}) { - std.Infoln(args...) -} - -// Warnln logs a message at level Warn on the standard logger. -func Warnln(args ...interface{}) { - std.Warnln(args...) -} - -// Warningln logs a message at level Warn on the standard logger. -func Warningln(args ...interface{}) { - std.Warningln(args...) -} - -// Errorln logs a message at level Error on the standard logger. -func Errorln(args ...interface{}) { - std.Errorln(args...) -} - -// Panicln logs a message at level Panic on the standard logger. -func Panicln(args ...interface{}) { - std.Panicln(args...) -} - -// Fatalln logs a message at level Fatal on the standard logger. -func Fatalln(args ...interface{}) { - std.Fatalln(args...) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go deleted file mode 100644 index 104d689f187eb50d9a4ab7d4142e94baf5cf6ed8..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go +++ /dev/null @@ -1,48 +0,0 @@ -package logrus - -import "time" - -const DefaultTimestampFormat = time.RFC3339 - -// The Formatter interface is used to implement a custom Formatter. It takes an -// `Entry`. It exposes all the fields, including the default ones: -// -// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. -// * `entry.Data["time"]`. The timestamp. -// * `entry.Data["level"]. The level the entry was logged at. -// -// Any additional fields added with `WithField` or `WithFields` are also in -// `entry.Data`. Format is expected to return an array of bytes which are then -// logged to `logger.Out`. -type Formatter interface { - Format(*Entry) ([]byte, error) -} - -// This is to not silently overwrite `time`, `msg` and `level` fields when -// dumping it. If this code wasn't there doing: -// -// logrus.WithField("level", 1).Info("hello") -// -// Would just silently drop the user provided level. Instead with this code -// it'll logged as: -// -// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} -// -// It's not exported because it's still using Data in an opinionated way. It's to -// avoid code duplication between the two default formatters. -func prefixFieldClashes(data Fields) { - _, ok := data["time"] - if ok { - data["fields.time"] = data["time"] - } - - _, ok = data["msg"] - if ok { - data["fields.msg"] = data["msg"] - } - - _, ok = data["level"] - if ok { - data["fields.level"] = data["level"] - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go deleted file mode 100644 index 6e5292785b1fb8769f979d6d66b993e6a4baef8f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go +++ /dev/null @@ -1,56 +0,0 @@ -package logstash - -import ( - "encoding/json" - "fmt" - - "github.com/sirupsen/logrus" -) - -// Formatter generates json in logstash format. -// Logstash site: http://logstash.net/ -type LogstashFormatter struct { - Type string // if not empty use for logstash type field. - - // TimestampFormat sets the format used for timestamps. - TimestampFormat string -} - -func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) { - entry.Data["@version"] = 1 - - if f.TimestampFormat == "" { - f.TimestampFormat = logrus.DefaultTimestampFormat - } - - entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat) - - // set message field - v, ok := entry.Data["message"] - if ok { - entry.Data["fields.message"] = v - } - entry.Data["message"] = entry.Message - - // set level field - v, ok = entry.Data["level"] - if ok { - entry.Data["fields.level"] = v - } - entry.Data["level"] = entry.Level.String() - - // set type field - if f.Type != "" { - v, ok = entry.Data["type"] - if ok { - entry.Data["fields.type"] = v - } - entry.Data["type"] = f.Type - } - - serialized, err := json.Marshal(entry.Data) - if err != nil { - return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) - } - return append(serialized, '\n'), nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go deleted file mode 100644 index 0da2b3653f5b8556ace1049e1a6b27258313511f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go +++ /dev/null @@ -1,34 +0,0 @@ -package logrus - -// A hook to be fired when logging on the logging levels returned from -// `Levels()` on your implementation of the interface. Note that this is not -// fired in a goroutine or a channel with workers, you should handle such -// functionality yourself if your call is non-blocking and you don't wish for -// the logging calls for levels returned from `Levels()` to block. -type Hook interface { - Levels() []Level - Fire(*Entry) error -} - -// Internal type for storing the hooks on a logger instance. -type levelHooks map[Level][]Hook - -// Add a hook to an instance of logger. This is called with -// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. -func (hooks levelHooks) Add(hook Hook) { - for _, level := range hook.Levels() { - hooks[level] = append(hooks[level], hook) - } -} - -// Fire all the hooks for the passed level. Used by `entry.log` to fire -// appropriate hooks for a log entry. -func (hooks levelHooks) Fire(level Level, entry *Entry) error { - for _, hook := range hooks[level] { - if err := hook.Fire(entry); err != nil { - return err - } - } - - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go deleted file mode 100644 index 1dc5a412475d80536fcfe252583042e06011f8cc..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go +++ /dev/null @@ -1,54 +0,0 @@ -package airbrake - -import ( - "errors" - "fmt" - - "github.com/sirupsen/logrus" - "github.com/tobi/airbrake-go" -) - -// AirbrakeHook to send exceptions to an exception-tracking service compatible -// with the Airbrake API. -type airbrakeHook struct { - APIKey string - Endpoint string - Environment string -} - -func NewHook(endpoint, apiKey, env string) *airbrakeHook { - return &airbrakeHook{ - APIKey: apiKey, - Endpoint: endpoint, - Environment: env, - } -} - -func (hook *airbrakeHook) Fire(entry *logrus.Entry) error { - airbrake.ApiKey = hook.APIKey - airbrake.Endpoint = hook.Endpoint - airbrake.Environment = hook.Environment - - var notifyErr error - err, ok := entry.Data["error"].(error) - if ok { - notifyErr = err - } else { - notifyErr = errors.New(entry.Message) - } - - airErr := airbrake.Notify(notifyErr) - if airErr != nil { - return fmt.Errorf("Failed to send error to Airbrake: %s", airErr) - } - - return nil -} - -func (hook *airbrakeHook) Levels() []logrus.Level { - return []logrus.Level{ - logrus.ErrorLevel, - logrus.FatalLevel, - logrus.PanicLevel, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go deleted file mode 100644 index fb9c9c9d172682eae3bde218a8dd4a68ea9496dc..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go +++ /dev/null @@ -1,68 +0,0 @@ -package logrus_bugsnag - -import ( - "errors" - - "github.com/sirupsen/logrus" - "github.com/bugsnag/bugsnag-go" -) - -type bugsnagHook struct{} - -// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before -// bugsnag.Configure. Bugsnag must be configured before the hook. -var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook") - -// ErrBugsnagSendFailed indicates that the hook failed to submit an error to -// bugsnag. The error was successfully generated, but `bugsnag.Notify()` -// failed. -type ErrBugsnagSendFailed struct { - err error -} - -func (e ErrBugsnagSendFailed) Error() string { - return "failed to send error to Bugsnag: " + e.err.Error() -} - -// NewBugsnagHook initializes a logrus hook which sends exceptions to an -// exception-tracking service compatible with the Bugsnag API. Before using -// this hook, you must call bugsnag.Configure(). The returned object should be -// registered with a log via `AddHook()` -// -// Entries that trigger an Error, Fatal or Panic should now include an "error" -// field to send to Bugsnag. -func NewBugsnagHook() (*bugsnagHook, error) { - if bugsnag.Config.APIKey == "" { - return nil, ErrBugsnagUnconfigured - } - return &bugsnagHook{}, nil -} - -// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the -// "error" field (or the Message if the error isn't present) and sends it off. -func (hook *bugsnagHook) Fire(entry *logrus.Entry) error { - var notifyErr error - err, ok := entry.Data["error"].(error) - if ok { - notifyErr = err - } else { - notifyErr = errors.New(entry.Message) - } - - bugsnagErr := bugsnag.Notify(notifyErr) - if bugsnagErr != nil { - return ErrBugsnagSendFailed{bugsnagErr} - } - - return nil -} - -// Levels enumerates the log levels on which the error should be forwarded to -// bugsnag: everything at or above the "Error" level. -func (hook *bugsnagHook) Levels() []logrus.Level { - return []logrus.Level{ - logrus.ErrorLevel, - logrus.FatalLevel, - logrus.PanicLevel, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go deleted file mode 100644 index c1549b21413c30df9b823e29080925dae9dd5dfe..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go +++ /dev/null @@ -1,55 +0,0 @@ -package logrus_papertrail - -import ( - "fmt" - "net" - "os" - "time" - - "github.com/sirupsen/logrus" -) - -const ( - format = "Jan 2 15:04:05" -) - -// PapertrailHook to send logs to a logging service compatible with the Papertrail API. -type PapertrailHook struct { - Host string - Port int - AppName string - UDPConn net.Conn -} - -// NewPapertrailHook creates a hook to be added to an instance of logger. -func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) { - conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port)) - return &PapertrailHook{host, port, appName, conn}, err -} - -// Fire is called when a log event is fired. -func (hook *PapertrailHook) Fire(entry *logrus.Entry) error { - date := time.Now().Format(format) - msg, _ := entry.String() - payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg) - - bytesWritten, err := hook.UDPConn.Write([]byte(payload)) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err) - return err - } - - return nil -} - -// Levels returns the available logging levels. -func (hook *PapertrailHook) Levels() []logrus.Level { - return []logrus.Level{ - logrus.PanicLevel, - logrus.FatalLevel, - logrus.ErrorLevel, - logrus.WarnLevel, - logrus.InfoLevel, - logrus.DebugLevel, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go deleted file mode 100644 index 4e29565ba9754c1ca67852d1d84c1e416d9485b2..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go +++ /dev/null @@ -1,100 +0,0 @@ -package logrus_sentry - -import ( - "fmt" - "time" - - "github.com/sirupsen/logrus" - "github.com/getsentry/raven-go" -) - -var ( - severityMap = map[logrus.Level]raven.Severity{ - logrus.DebugLevel: raven.DEBUG, - logrus.InfoLevel: raven.INFO, - logrus.WarnLevel: raven.WARNING, - logrus.ErrorLevel: raven.ERROR, - logrus.FatalLevel: raven.FATAL, - logrus.PanicLevel: raven.FATAL, - } -) - -func getAndDel(d logrus.Fields, key string) (string, bool) { - var ( - ok bool - v interface{} - val string - ) - if v, ok = d[key]; !ok { - return "", false - } - - if val, ok = v.(string); !ok { - return "", false - } - delete(d, key) - return val, true -} - -// SentryHook delivers logs to a sentry server. -type SentryHook struct { - // Timeout sets the time to wait for a delivery error from the sentry server. - // If this is set to zero the server will not wait for any response and will - // consider the message correctly sent - Timeout time.Duration - - client *raven.Client - levels []logrus.Level -} - -// NewSentryHook creates a hook to be added to an instance of logger -// and initializes the raven client. -// This method sets the timeout to 100 milliseconds. -func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) { - client, err := raven.NewClient(DSN, nil) - if err != nil { - return nil, err - } - return &SentryHook{100 * time.Millisecond, client, levels}, nil -} - -// Called when an event should be sent to sentry -// Special fields that sentry uses to give more information to the server -// are extracted from entry.Data (if they are found) -// These fields are: logger and server_name -func (hook *SentryHook) Fire(entry *logrus.Entry) error { - packet := &raven.Packet{ - Message: entry.Message, - Timestamp: raven.Timestamp(entry.Time), - Level: severityMap[entry.Level], - Platform: "go", - } - - d := entry.Data - - if logger, ok := getAndDel(d, "logger"); ok { - packet.Logger = logger - } - if serverName, ok := getAndDel(d, "server_name"); ok { - packet.ServerName = serverName - } - packet.Extra = map[string]interface{}(d) - - _, errCh := hook.client.Capture(packet, nil) - timeout := hook.Timeout - if timeout != 0 { - timeoutCh := time.After(timeout) - select { - case err := <-errCh: - return err - case <-timeoutCh: - return fmt.Errorf("no response from sentry server in %s", timeout) - } - } - return nil -} - -// Levels returns the available logging levels. -func (hook *SentryHook) Levels() []logrus.Level { - return hook.levels -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go deleted file mode 100644 index 430f646e888eb96653a45fbfc2125ead0f2752dc..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go +++ /dev/null @@ -1,59 +0,0 @@ -package logrus_syslog - -import ( - "fmt" - "github.com/sirupsen/logrus" - "log/syslog" - "os" -) - -// SyslogHook to send logs via syslog. -type SyslogHook struct { - Writer *syslog.Writer - SyslogNetwork string - SyslogRaddr string -} - -// Creates a hook to be added to an instance of logger. This is called with -// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` -// `if err == nil { log.Hooks.Add(hook) }` -func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { - w, err := syslog.Dial(network, raddr, priority, tag) - return &SyslogHook{w, network, raddr}, err -} - -func (hook *SyslogHook) Fire(entry *logrus.Entry) error { - line, err := entry.String() - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) - return err - } - - switch entry.Level { - case logrus.PanicLevel: - return hook.Writer.Crit(line) - case logrus.FatalLevel: - return hook.Writer.Crit(line) - case logrus.ErrorLevel: - return hook.Writer.Err(line) - case logrus.WarnLevel: - return hook.Writer.Warning(line) - case logrus.InfoLevel: - return hook.Writer.Info(line) - case logrus.DebugLevel: - return hook.Writer.Debug(line) - default: - return nil - } -} - -func (hook *SyslogHook) Levels() []logrus.Level { - return []logrus.Level{ - logrus.PanicLevel, - logrus.FatalLevel, - logrus.ErrorLevel, - logrus.WarnLevel, - logrus.InfoLevel, - logrus.DebugLevel, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go deleted file mode 100644 index e733b0a1a3ccbdc9f92e8a5a8f267d58cfae1630..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go +++ /dev/null @@ -1,40 +0,0 @@ -package logrus - -import ( - "encoding/json" - "fmt" -) - -type JSONFormatter struct { - // TimestampFormat sets the format used for marshaling timestamps. - TimestampFormat string -} - -func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { - data := make(Fields, len(entry.Data)+3) - for k, v := range entry.Data { - switch v := v.(type) { - case error: - // Otherwise errors are ignored by `encoding/json` - // https://github.com/sirupsen/logrus/issues/137 - data[k] = v.Error() - default: - data[k] = v - } - } - prefixFieldClashes(data) - - if f.TimestampFormat == "" { - f.TimestampFormat = DefaultTimestampFormat - } - - data["time"] = entry.Time.Format(f.TimestampFormat) - data["msg"] = entry.Message - data["level"] = entry.Level.String() - - serialized, err := json.Marshal(data) - if err != nil { - return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) - } - return append(serialized, '\n'), nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go deleted file mode 100644 index da928a37509902f61d3214b2e1beb1b4753e514a..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go +++ /dev/null @@ -1,203 +0,0 @@ -package logrus - -import ( - "io" - "os" - "sync" -) - -type Logger struct { - // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a - // file, or leave it default which is `os.Stdout`. You can also set this to - // something more adventorous, such as logging to Kafka. - Out io.Writer - // Hooks for the logger instance. These allow firing events based on logging - // levels and log entries. For example, to send errors to an error tracking - // service, log to StatsD or dump the core on fatal errors. - Hooks levelHooks - // All log entries pass through the formatter before logged to Out. The - // included formatters are `TextFormatter` and `JSONFormatter` for which - // TextFormatter is the default. In development (when a TTY is attached) it - // logs with colors, but to a file it wouldn't. You can easily implement your - // own that implements the `Formatter` interface, see the `README` or included - // formatters for examples. - Formatter Formatter - // The logging level the logger should log at. This is typically (and defaults - // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be - // logged. `logrus.Debug` is useful in - Level Level - // Used to sync writing to the log. - mu sync.Mutex -} - -// Creates a new logger. Configuration should be set by changing `Formatter`, -// `Out` and `Hooks` directly on the default logger instance. You can also just -// instantiate your own: -// -// var log = &Logger{ -// Out: os.Stderr, -// Formatter: new(JSONFormatter), -// Hooks: make(levelHooks), -// Level: logrus.DebugLevel, -// } -// -// It's recommended to make this a global instance called `log`. -func New() *Logger { - return &Logger{ - Out: os.Stdout, - Formatter: new(TextFormatter), - Hooks: make(levelHooks), - Level: InfoLevel, - } -} - -// Adds a field to the log entry, note that you it doesn't log until you call -// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. -// Ff you want multiple fields, use `WithFields`. -func (logger *Logger) WithField(key string, value interface{}) *Entry { - return NewEntry(logger).WithField(key, value) -} - -// Adds a struct of fields to the log entry. All it does is call `WithField` for -// each `Field`. -func (logger *Logger) WithFields(fields Fields) *Entry { - return NewEntry(logger).WithFields(fields) -} - -func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.Level >= DebugLevel { - NewEntry(logger).Debugf(format, args...) - } -} - -func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.Level >= InfoLevel { - NewEntry(logger).Infof(format, args...) - } -} - -func (logger *Logger) Printf(format string, args ...interface{}) { - NewEntry(logger).Printf(format, args...) -} - -func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warnf(format, args...) - } -} - -func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warnf(format, args...) - } -} - -func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.Level >= ErrorLevel { - NewEntry(logger).Errorf(format, args...) - } -} - -func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.Level >= FatalLevel { - NewEntry(logger).Fatalf(format, args...) - } -} - -func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.Level >= PanicLevel { - NewEntry(logger).Panicf(format, args...) - } -} - -func (logger *Logger) Debug(args ...interface{}) { - if logger.Level >= DebugLevel { - NewEntry(logger).Debug(args...) - } -} - -func (logger *Logger) Info(args ...interface{}) { - if logger.Level >= InfoLevel { - NewEntry(logger).Info(args...) - } -} - -func (logger *Logger) Print(args ...interface{}) { - NewEntry(logger).Info(args...) -} - -func (logger *Logger) Warn(args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warn(args...) - } -} - -func (logger *Logger) Warning(args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warn(args...) - } -} - -func (logger *Logger) Error(args ...interface{}) { - if logger.Level >= ErrorLevel { - NewEntry(logger).Error(args...) - } -} - -func (logger *Logger) Fatal(args ...interface{}) { - if logger.Level >= FatalLevel { - NewEntry(logger).Fatal(args...) - } -} - -func (logger *Logger) Panic(args ...interface{}) { - if logger.Level >= PanicLevel { - NewEntry(logger).Panic(args...) - } -} - -func (logger *Logger) Debugln(args ...interface{}) { - if logger.Level >= DebugLevel { - NewEntry(logger).Debugln(args...) - } -} - -func (logger *Logger) Infoln(args ...interface{}) { - if logger.Level >= InfoLevel { - NewEntry(logger).Infoln(args...) - } -} - -func (logger *Logger) Println(args ...interface{}) { - NewEntry(logger).Println(args...) -} - -func (logger *Logger) Warnln(args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warnln(args...) - } -} - -func (logger *Logger) Warningln(args ...interface{}) { - if logger.Level >= WarnLevel { - NewEntry(logger).Warnln(args...) - } -} - -func (logger *Logger) Errorln(args ...interface{}) { - if logger.Level >= ErrorLevel { - NewEntry(logger).Errorln(args...) - } -} - -func (logger *Logger) Fatalln(args ...interface{}) { - if logger.Level >= FatalLevel { - NewEntry(logger).Fatalln(args...) - } -} - -func (logger *Logger) Panicln(args ...interface{}) { - if logger.Level >= PanicLevel { - NewEntry(logger).Panicln(args...) - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go deleted file mode 100644 index 43ee12e90e7b47401927cf787b3bd20fd45869e4..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go +++ /dev/null @@ -1,94 +0,0 @@ -package logrus - -import ( - "fmt" - "log" -) - -// Fields type, used to pass to `WithFields`. -type Fields map[string]interface{} - -// Level type -type Level uint8 - -// Convert the Level to a string. E.g. PanicLevel becomes "panic". -func (level Level) String() string { - switch level { - case DebugLevel: - return "debug" - case InfoLevel: - return "info" - case WarnLevel: - return "warning" - case ErrorLevel: - return "error" - case FatalLevel: - return "fatal" - case PanicLevel: - return "panic" - } - - return "unknown" -} - -// ParseLevel takes a string level and returns the Logrus log level constant. -func ParseLevel(lvl string) (Level, error) { - switch lvl { - case "panic": - return PanicLevel, nil - case "fatal": - return FatalLevel, nil - case "error": - return ErrorLevel, nil - case "warn", "warning": - return WarnLevel, nil - case "info": - return InfoLevel, nil - case "debug": - return DebugLevel, nil - } - - var l Level - return l, fmt.Errorf("not a valid logrus Level: %q", lvl) -} - -// These are the different logging levels. You can set the logging level to log -// on your instance of logger, obtained with `logrus.New()`. -const ( - // PanicLevel level, highest level of severity. Logs and then calls panic with the - // message passed to Debug, Info, ... - PanicLevel Level = iota - // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the - // logging level is set to Panic. - FatalLevel - // ErrorLevel level. Logs. Used for errors that should definitely be noted. - // Commonly used for hooks to send errors to an error tracking service. - ErrorLevel - // WarnLevel level. Non-critical entries that deserve eyes. - WarnLevel - // InfoLevel level. General operational entries about what's going on inside the - // application. - InfoLevel - // DebugLevel level. Usually only enabled when debugging. Very verbose logging. - DebugLevel -) - -// Won't compile if StdLogger can't be realized by a log.Logger -var _ StdLogger = &log.Logger{} - -// StdLogger is what your logrus-enabled library should take, that way -// it'll accept a stdlib logger and a logrus logger. There's no standard -// interface, this is the closest we get, unfortunately. -type StdLogger interface { - Print(...interface{}) - Printf(string, ...interface{}) - Println(...interface{}) - - Fatal(...interface{}) - Fatalf(string, ...interface{}) - Fatalln(...interface{}) - - Panic(...interface{}) - Panicf(string, ...interface{}) - Panicln(...interface{}) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go deleted file mode 100644 index 8fe02a4aec1ac4b7228a0af24fb8df6622f8f2da..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go +++ /dev/null @@ -1,12 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logrus - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go deleted file mode 100644 index 0428ee5d52a6d2429120bf5a0540f3ca23e7ebba..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go +++ /dev/null @@ -1,20 +0,0 @@ -/* - Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. -*/ -package logrus - -import ( - "syscall" -) - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]uint8 - Ispeed uint32 - Ospeed uint32 -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go deleted file mode 100644 index a2c0b40db612b7c1be1646a5480eb1f6f646060e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go +++ /dev/null @@ -1,12 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logrus - -import "syscall" - -const ioctlReadTermios = syscall.TCGETS - -type Termios syscall.Termios diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go deleted file mode 100644 index b8bebc13eea6547985131671c556c3b5c44aa57c..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go +++ /dev/null @@ -1,21 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux darwin freebsd openbsd - -package logrus - -import ( - "syscall" - "unsafe" -) - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal() bool { - fd := syscall.Stdout - var termios Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go deleted file mode 100644 index af609a53d6492443e6a664a8b81a82db2d7e05d3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package logrus - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go deleted file mode 100644 index 2e09f6f7e31d23314dc00f879b92619f76fe23f5..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package logrus - -import ( - "syscall" - "unsafe" -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal() bool { - fd := syscall.Stdout - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go deleted file mode 100644 index 612417ff9c846d2d208248ec39b044f0c940f094..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go +++ /dev/null @@ -1,149 +0,0 @@ -package logrus - -import ( - "bytes" - "fmt" - "sort" - "strings" - "time" -) - -const ( - nocolor = 0 - red = 31 - green = 32 - yellow = 33 - blue = 34 - gray = 37 -) - -var ( - baseTimestamp time.Time - isTerminal bool -) - -func init() { - baseTimestamp = time.Now() - isTerminal = IsTerminal() -} - -func miniTS() int { - return int(time.Since(baseTimestamp) / time.Second) -} - -type TextFormatter struct { - // Set to true to bypass checking for a TTY before outputting colors. - ForceColors bool - - // Force disabling colors. - DisableColors bool - - // Disable timestamp logging. useful when output is redirected to logging - // system that already adds timestamps. - DisableTimestamp bool - - // Enable logging the full timestamp when a TTY is attached instead of just - // the time passed since beginning of execution. - FullTimestamp bool - - // TimestampFormat to use for display when a full timestamp is printed - TimestampFormat string - - // The fields are sorted by default for a consistent output. For applications - // that log extremely frequently and don't use the JSON formatter this may not - // be desired. - DisableSorting bool -} - -func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - var keys []string = make([]string, 0, len(entry.Data)) - for k := range entry.Data { - keys = append(keys, k) - } - - if !f.DisableSorting { - sort.Strings(keys) - } - - b := &bytes.Buffer{} - - prefixFieldClashes(entry.Data) - - isColored := (f.ForceColors || isTerminal) && !f.DisableColors - - if f.TimestampFormat == "" { - f.TimestampFormat = DefaultTimestampFormat - } - if isColored { - f.printColored(b, entry, keys) - } else { - if !f.DisableTimestamp { - f.appendKeyValue(b, "time", entry.Time.Format(f.TimestampFormat)) - } - f.appendKeyValue(b, "level", entry.Level.String()) - f.appendKeyValue(b, "msg", entry.Message) - for _, key := range keys { - f.appendKeyValue(b, key, entry.Data[key]) - } - } - - b.WriteByte('\n') - return b.Bytes(), nil -} - -func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string) { - var levelColor int - switch entry.Level { - case DebugLevel: - levelColor = gray - case WarnLevel: - levelColor = yellow - case ErrorLevel, FatalLevel, PanicLevel: - levelColor = red - default: - levelColor = blue - } - - levelText := strings.ToUpper(entry.Level.String())[0:4] - - if !f.FullTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) - } else { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(f.TimestampFormat), entry.Message) - } - for _, k := range keys { - v := entry.Data[k] - fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v) - } -} - -func needsQuoting(text string) bool { - for _, ch := range text { - if !((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || - ch == '-' || ch == '.') { - return false - } - } - return true -} - -func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) { - switch value.(type) { - case string: - if needsQuoting(value.(string)) { - fmt.Fprintf(b, "%v=%s ", key, value) - } else { - fmt.Fprintf(b, "%v=%q ", key, value) - } - case error: - if needsQuoting(value.(error).Error()) { - fmt.Fprintf(b, "%v=%s ", key, value) - } else { - fmt.Fprintf(b, "%v=%q ", key, value) - } - default: - fmt.Fprintf(b, "%v=%v ", key, value) - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go deleted file mode 100644 index 1e30b1c753a7425ea10c7c6cb9f3762a661b519b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go +++ /dev/null @@ -1,31 +0,0 @@ -package logrus - -import ( - "bufio" - "io" - "runtime" -) - -func (logger *Logger) Writer() *io.PipeWriter { - reader, writer := io.Pipe() - - go logger.writerScanner(reader) - runtime.SetFinalizer(writer, writerFinalizer) - - return writer -} - -func (logger *Logger) writerScanner(reader *io.PipeReader) { - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - logger.Print(scanner.Text()) - } - if err := scanner.Err(); err != nil { - logger.Errorf("Error while reading from Writer: %s", err) - } - reader.Close() -} - -func writerFinalizer(writer *io.PipeWriter) { - writer.Close() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE deleted file mode 100644 index 5515ccfb716e0db1de7ab629502abe8a44a5faa5..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (C) 2013 Jeremy Saenz -All Rights Reserved. - -MIT LICENSE - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/app.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/app.go deleted file mode 100644 index 2f992d0d7a79b1d4fb895c5feeced4b174ca559e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/app.go +++ /dev/null @@ -1,334 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path" - "time" -) - -// App is the main structure of a cli application. It is recomended that -// an app be created with the cli.NewApp() function -type App struct { - // The name of the program. Defaults to path.Base(os.Args[0]) - Name string - // Full name of command for help, defaults to Name - HelpName string - // Description of the program. - Usage string - // Description of the program argument format. - ArgsUsage string - // Version of the program - Version string - // List of commands to execute - Commands []Command - // List of flags to parse - Flags []Flag - // Boolean to enable bash completion commands - EnableBashCompletion bool - // Boolean to hide built-in help command - HideHelp bool - // Boolean to hide built-in version flag - HideVersion bool - // An action to execute when the bash-completion flag is set - BashComplete func(context *Context) - // An action to execute before any subcommands are run, but after the context is ready - // If a non-nil error is returned, no subcommands are run - Before func(context *Context) error - // An action to execute after any subcommands are run, but after the subcommand has finished - // It is run even if Action() panics - After func(context *Context) error - // The action to execute when no subcommands are specified - Action func(context *Context) - // Execute this function if the proper command cannot be found - CommandNotFound func(context *Context, command string) - // Compilation date - Compiled time.Time - // List of all authors who contributed - Authors []Author - // Copyright of the binary if any - Copyright string - // Name of Author (Note: Use App.Authors, this is deprecated) - Author string - // Email of Author (Note: Use App.Authors, this is deprecated) - Email string - // Writer writer to write output to - Writer io.Writer -} - -// Tries to find out when this binary was compiled. -// Returns the current time if it fails to find it. -func compileTime() time.Time { - info, err := os.Stat(os.Args[0]) - if err != nil { - return time.Now() - } - return info.ModTime() -} - -// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. -func NewApp() *App { - return &App{ - Name: path.Base(os.Args[0]), - HelpName: path.Base(os.Args[0]), - Usage: "A new cli application", - Version: "0.0.0", - BashComplete: DefaultAppComplete, - Action: helpCommand.Action, - Compiled: compileTime(), - Writer: os.Stdout, - } -} - -// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination -func (a *App) Run(arguments []string) (err error) { - if a.Author != "" || a.Email != "" { - a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) - } - - newCmds := []Command{} - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - // append help to commands - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - - //append version/help flags - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) - } - - if !a.HideVersion { - a.appendFlag(VersionFlag) - } - - // parse flags - set := flagSet(a.Name, a.Flags) - set.SetOutput(ioutil.Discard) - err = set.Parse(arguments[1:]) - nerr := normalizeFlags(a.Flags, set) - if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - context := NewContext(a, set, nil) - ShowAppHelp(context) - return nerr - } - context := NewContext(a, set, nil) - - if checkCompletions(context) { - return nil - } - - if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) - ShowAppHelp(context) - return err - } - - if !a.HideHelp && checkHelp(context) { - ShowAppHelp(context) - return nil - } - - if !a.HideVersion && checkVersion(context) { - ShowVersion(context) - return nil - } - - if a.After != nil { - defer func() { - afterErr := a.After(context) - if afterErr != nil { - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil { - err := a.Before(context) - if err != nil { - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - // Run default Action - a.Action(context) - return nil -} - -// Another entry point to the cli app, takes care of passing arguments and error handling -func (a *App) RunAndExitOnError() { - if err := a.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags -func (a *App) RunAsSubcommand(ctx *Context) (err error) { - // append help to commands - if len(a.Commands) > 0 { - if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { - a.appendFlag(HelpFlag) - } - } - } - - newCmds := []Command{} - for _, c := range a.Commands { - if c.HelpName == "" { - c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) - } - newCmds = append(newCmds, c) - } - a.Commands = newCmds - - // append flags - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) - } - - // parse flags - set := flagSet(a.Name, a.Flags) - set.SetOutput(ioutil.Discard) - err = set.Parse(ctx.Args().Tail()) - nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, ctx) - - if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - fmt.Fprintln(a.Writer) - if len(a.Commands) > 0 { - ShowSubcommandHelp(context) - } else { - ShowCommandHelp(ctx, context.Args().First()) - } - return nerr - } - - if checkCompletions(context) { - return nil - } - - if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) - ShowSubcommandHelp(context) - return err - } - - if len(a.Commands) > 0 { - if checkSubcommandHelp(context) { - return nil - } - } else { - if checkCommandHelp(ctx, context.Args().First()) { - return nil - } - } - - if a.After != nil { - defer func() { - afterErr := a.After(context) - if afterErr != nil { - if err != nil { - err = NewMultiError(err, afterErr) - } else { - err = afterErr - } - } - }() - } - - if a.Before != nil { - err := a.Before(context) - if err != nil { - return err - } - } - - args := context.Args() - if args.Present() { - name := args.First() - c := a.Command(name) - if c != nil { - return c.Run(context) - } - } - - // Run default Action - a.Action(context) - - return nil -} - -// Returns the named command on App. Returns nil if the command does not exist -func (a *App) Command(name string) *Command { - for _, c := range a.Commands { - if c.HasName(name) { - return &c - } - } - - return nil -} - -func (a *App) hasFlag(flag Flag) bool { - for _, f := range a.Flags { - if flag == f { - return true - } - } - - return false -} - -func (a *App) appendFlag(flag Flag) { - if !a.hasFlag(flag) { - a.Flags = append(a.Flags, flag) - } -} - -// Author represents someone who has contributed to a cli project. -type Author struct { - Name string // The Authors name - Email string // The Authors email -} - -// String makes Author comply to the Stringer interface, to allow an easy print in the templating process -func (a Author) String() string { - e := "" - if a.Email != "" { - e = "<" + a.Email + "> " - } - - return fmt.Sprintf("%v %v", a.Name, e) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go deleted file mode 100644 index 31dc9124d1eb6d1291cf94a4be695eb8ca945170..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go +++ /dev/null @@ -1,40 +0,0 @@ -// Package cli provides a minimal framework for creating and organizing command line -// Go applications. cli is designed to be easy to understand and write, the most simple -// cli application can be written as follows: -// func main() { -// cli.NewApp().Run(os.Args) -// } -// -// Of course this application does not do much, so let's make this an actual application: -// func main() { -// app := cli.NewApp() -// app.Name = "greet" -// app.Usage = "say a greeting" -// app.Action = func(c *cli.Context) { -// println("Greetings") -// } -// -// app.Run(os.Args) -// } -package cli - -import ( - "strings" -) - -type MultiError struct { - Errors []error -} - -func NewMultiError(err ...error) MultiError { - return MultiError{Errors: err} -} - -func (m MultiError) Error() string { - errs := make([]string, len(m.Errors)) - for i, err := range m.Errors { - errs[i] = err.Error() - } - - return strings.Join(errs, "\n") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/command.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/command.go deleted file mode 100644 index 824e77bae3f5d5175e3258fcc29faeeda6acd15a..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/command.go +++ /dev/null @@ -1,216 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "strings" -) - -// Command is a subcommand for a cli.App. -type Command struct { - // The name of the command - Name string - // short name of the command. Typically one character (deprecated, use `Aliases`) - ShortName string - // A list of aliases for the command - Aliases []string - // A short description of the usage of this command - Usage string - // A longer explanation of how the command works - Description string - // A short description of the arguments of this command - ArgsUsage string - // The function to call when checking for bash command completions - BashComplete func(context *Context) - // An action to execute before any sub-subcommands are run, but after the context is ready - // If a non-nil error is returned, no sub-subcommands are run - Before func(context *Context) error - // An action to execute after any subcommands are run, but after the subcommand has finished - // It is run even if Action() panics - After func(context *Context) error - // The function to call when this command is invoked - Action func(context *Context) - // List of child commands - Subcommands []Command - // List of flags to parse - Flags []Flag - // Treat all flags as normal arguments if true - SkipFlagParsing bool - // Boolean to hide built-in help command - HideHelp bool - - // Full name of command for help, defaults to full command name, including parent commands. - HelpName string - commandNamePath []string -} - -// Returns the full name of the command. -// For subcommands this ensures that parent commands are part of the command path -func (c Command) FullName() string { - if c.commandNamePath == nil { - return c.Name - } - return strings.Join(c.commandNamePath, " ") -} - -// Invokes the command given the context, parses ctx.Args() to generate command-specific flags -func (c Command) Run(ctx *Context) error { - if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil { - return c.startApp(ctx) - } - - if !c.HideHelp && (HelpFlag != BoolFlag{}) { - // append help to flags - c.Flags = append( - c.Flags, - HelpFlag, - ) - } - - if ctx.App.EnableBashCompletion { - c.Flags = append(c.Flags, BashCompletionFlag) - } - - set := flagSet(c.Name, c.Flags) - set.SetOutput(ioutil.Discard) - - var err error - if !c.SkipFlagParsing { - firstFlagIndex := -1 - terminatorIndex := -1 - for index, arg := range ctx.Args() { - if arg == "--" { - terminatorIndex = index - break - } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { - firstFlagIndex = index - } - } - - if firstFlagIndex > -1 { - args := ctx.Args() - regularArgs := make([]string, len(args[1:firstFlagIndex])) - copy(regularArgs, args[1:firstFlagIndex]) - - var flagArgs []string - if terminatorIndex > -1 { - flagArgs = args[firstFlagIndex:terminatorIndex] - regularArgs = append(regularArgs, args[terminatorIndex:]...) - } else { - flagArgs = args[firstFlagIndex:] - } - - err = set.Parse(append(flagArgs, regularArgs...)) - } else { - err = set.Parse(ctx.Args().Tail()) - } - } else { - if c.SkipFlagParsing { - err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) - } - } - - if err != nil { - fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return err - } - - nerr := normalizeFlags(c.Flags, set) - if nerr != nil { - fmt.Fprintln(ctx.App.Writer, nerr) - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return nerr - } - context := NewContext(ctx.App, set, ctx) - - if checkCommandCompletions(context, c.Name) { - return nil - } - - if checkCommandHelp(context, c.Name) { - return nil - } - context.Command = c - c.Action(context) - return nil -} - -func (c Command) Names() []string { - names := []string{c.Name} - - if c.ShortName != "" { - names = append(names, c.ShortName) - } - - return append(names, c.Aliases...) -} - -// Returns true if Command.Name or Command.ShortName matches given name -func (c Command) HasName(name string) bool { - for _, n := range c.Names() { - if n == name { - return true - } - } - return false -} - -func (c Command) startApp(ctx *Context) error { - app := NewApp() - - // set the name and usage - app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) - if c.HelpName == "" { - app.HelpName = c.HelpName - } else { - app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) - } - - if c.Description != "" { - app.Usage = c.Description - } else { - app.Usage = c.Usage - } - - // set CommandNotFound - app.CommandNotFound = ctx.App.CommandNotFound - - // set the flags and commands - app.Commands = c.Subcommands - app.Flags = c.Flags - app.HideHelp = c.HideHelp - - app.Version = ctx.App.Version - app.HideVersion = ctx.App.HideVersion - app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email - app.Writer = ctx.App.Writer - - // bash completion - app.EnableBashCompletion = ctx.App.EnableBashCompletion - if c.BashComplete != nil { - app.BashComplete = c.BashComplete - } - - // set the actions - app.Before = c.Before - app.After = c.After - if c.Action != nil { - app.Action = c.Action - } else { - app.Action = helpSubcommand.Action - } - - var newCmds []Command - for _, cc := range app.Commands { - cc.commandNamePath = []string{c.Name, cc.Name} - newCmds = append(newCmds, cc) - } - app.Commands = newCmds - - return app.RunAsSubcommand(ctx) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/context.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/context.go deleted file mode 100644 index 0513d34f61ec9ab41b400cf10731287609dd9fdf..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/context.go +++ /dev/null @@ -1,388 +0,0 @@ -package cli - -import ( - "errors" - "flag" - "strconv" - "strings" - "time" -) - -// Context is a type that is passed through to -// each Handler action in a cli application. Context -// can be used to retrieve context-specific Args and -// parsed command-line options. -type Context struct { - App *App - Command Command - flagSet *flag.FlagSet - setFlags map[string]bool - globalSetFlags map[string]bool - parentContext *Context -} - -// Creates a new context. For use in when invoking an App or Command action. -func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - return &Context{App: app, flagSet: set, parentContext: parentCtx} -} - -// Looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// Looks up the value of a local bool flag, returns false if no bool flag exists -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// Looks up the value of a local boolT flag, returns false if no bool flag exists -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// Looks up the value of a local string flag, returns "" if no string flag exists -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// Looks up the value of a local string slice flag, returns nil if no string slice flag exists -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// Looks up the value of a local int slice flag, returns nil if no int slice flag exists -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// Looks up the value of a local generic flag, returns nil if no generic flag exists -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// Looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt(name, fs) - } - return 0 -} - -// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -// Looks up the value of a global bool flag, returns false if no bool flag exists -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -// Looks up the value of a global string flag, returns "" if no string flag exists -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -// Looks up the value of a global string slice flag, returns nil if no string slice flag exists -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -// Looks up the value of a global int slice flag, returns nil if no int slice flag exists -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -// Looks up the value of a global generic flag, returns nil if no generic flag exists -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - -// Returns the number of flags set -func (c *Context) NumFlags() int { - return c.flagSet.NFlag() -} - -// Determines if the flag was actually set -func (c *Context) IsSet(name string) bool { - if c.setFlags == nil { - c.setFlags = make(map[string]bool) - c.flagSet.Visit(func(f *flag.Flag) { - c.setFlags[f.Name] = true - }) - } - return c.setFlags[name] == true -} - -// Determines if the global flag was actually set -func (c *Context) GlobalIsSet(name string) bool { - if c.globalSetFlags == nil { - c.globalSetFlags = make(map[string]bool) - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { - ctx.flagSet.Visit(func(f *flag.Flag) { - c.globalSetFlags[f.Name] = true - }) - } - } - return c.globalSetFlags[name] -} - -// Returns a slice of flag names used in this context. -func (c *Context) FlagNames() (names []string) { - for _, flag := range c.Command.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" { - continue - } - names = append(names, name) - } - return -} - -// Returns a slice of global flag names used by the app. -func (c *Context) GlobalFlagNames() (names []string) { - for _, flag := range c.App.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" || name == "version" { - continue - } - names = append(names, name) - } - return -} - -// Returns the parent context, if any -func (c *Context) Parent() *Context { - return c.parentContext -} - -type Args []string - -// Returns the command line arguments associated with the context. -func (c *Context) Args() Args { - args := Args(c.flagSet.Args()) - return args -} - -// Returns the nth argument, or else a blank string -func (a Args) Get(n int) string { - if len(a) > n { - return a[n] - } - return "" -} - -// Returns the first argument, or else a blank string -func (a Args) First() string { - return a.Get(0) -} - -// Return the rest of the arguments (not the first one) -// or else an empty string slice -func (a Args) Tail() []string { - if len(a) >= 2 { - return []string(a)[1:] - } - return []string{} -} - -// Checks if there are any arguments present -func (a Args) Present() bool { - return len(a) != 0 -} - -// Swaps arguments at the given indexes -func (a Args) Swap(from, to int) error { - if from >= len(a) || to >= len(a) { - return errors.New("index out of range") - } - a[from], a[to] = a[to], a[from] - return nil -} - -func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil; ctx = ctx.parentContext { - if f := ctx.flagSet.Lookup(name); f != nil { - return ctx.flagSet - } - } - return nil -} - -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - val, err := strconv.Atoi(f.Value.String()) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - val, err := time.ParseDuration(f.Value.String()) - if err == nil { - return val - } - } - - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - return f.Value.String() - } - - return "" -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*StringSlice)).Value() - - } - - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*IntSlice)).Value() - - } - - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - return f.Value - } - return nil -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return val - } - - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return true - } - return val - } - - return false -} - -func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { - switch ff.Value.(type) { - case *StringSlice: - default: - set.Set(name, ff.Value.String()) - } -} - -func normalizeFlags(flags []Flag, set *flag.FlagSet) error { - visited := make(map[string]bool) - set.Visit(func(f *flag.Flag) { - visited[f.Name] = true - }) - for _, f := range flags { - parts := strings.Split(f.GetName(), ",") - if len(parts) == 1 { - continue - } - var ff *flag.Flag - for _, name := range parts { - name = strings.Trim(name, " ") - if visited[name] { - if ff != nil { - return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) - } - ff = set.Lookup(name) - } - } - if ff == nil { - continue - } - for _, name := range parts { - name = strings.Trim(name, " ") - if !visited[name] { - copyFlag(name, ff, set) - } - } - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go deleted file mode 100644 index 49f30994ea6bbaa06fe36e487e0a1f91431f67d1..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go +++ /dev/null @@ -1,527 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "os" - "strconv" - "strings" - "time" -) - -// This flag enables bash-completion for all commands and subcommands -var BashCompletionFlag = BoolFlag{ - Name: "generate-bash-completion", -} - -// This flag prints the version for the application -var VersionFlag = BoolFlag{ - Name: "version, v", - Usage: "print the version", -} - -// This flag prints the help for all commands and subcommands -// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand -// unless HideHelp is set to true) -var HelpFlag = BoolFlag{ - Name: "help, h", - Usage: "show help", -} - -// Flag is a common interface related to parsing flags in cli. -// For more advanced flag parsing techniques, it is recomended that -// this interface be implemented. -type Flag interface { - fmt.Stringer - // Apply Flag settings to the given flag set - Apply(*flag.FlagSet) - GetName() string -} - -func flagSet(name string, flags []Flag) *flag.FlagSet { - set := flag.NewFlagSet(name, flag.ContinueOnError) - - for _, f := range flags { - f.Apply(set) - } - return set -} - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} - -// Generic is a generic parseable type identified by a specific flag -type Generic interface { - Set(value string) error - String() string -} - -// GenericFlag is the flag type for types implementing Generic -type GenericFlag struct { - Name string - Value Generic - Usage string - EnvVar string -} - -// String returns the string representation of the generic flag to display the -// help text to the user (uses the String() method of the generic flag to show -// the value) -func (f GenericFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage)) -} - -// Apply takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -func (f GenericFlag) Apply(set *flag.FlagSet) { - val := f.Value - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - val.Set(envVal) - break - } - } - } - - eachName(f.Name, func(name string) { - set.Var(f.Value, name, f.Usage) - }) -} - -func (f GenericFlag) GetName() string { - return f.Name -} - -// StringSlice is an opaque type for []string to satisfy flag.Value -type StringSlice []string - -// Set appends the string value to the list of values -func (f *StringSlice) Set(value string) error { - *f = append(*f, value) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *StringSlice) String() string { - return fmt.Sprintf("%s", *f) -} - -// Value returns the slice of strings set by this flag -func (f *StringSlice) Value() []string { - return *f -} - -// StringSlice is a string flag that can be specified multiple times on the -// command-line -type StringSliceFlag struct { - Name string - Value *StringSlice - Usage string - EnvVar string -} - -// String returns the usage -func (f StringSliceFlag) String() string { - firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") - pref := prefixFor(firstName) - return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f StringSliceFlag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - newVal := &StringSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - newVal.Set(s) - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &StringSlice{} - } - set.Var(f.Value, name, f.Usage) - }) -} - -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// StringSlice is an opaque type for []int to satisfy flag.Value -type IntSlice []int - -// Set parses the value into an integer and appends it to the list of values -func (f *IntSlice) Set(value string) error { - tmp, err := strconv.Atoi(value) - if err != nil { - return err - } else { - *f = append(*f, tmp) - } - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *IntSlice) String() string { - return fmt.Sprintf("%d", *f) -} - -// Value returns the slice of ints set by this flag -func (f *IntSlice) Value() []int { - return *f -} - -// IntSliceFlag is an int flag that can be specified multiple times on the -// command-line -type IntSliceFlag struct { - Name string - Value *IntSlice - Usage string - EnvVar string -} - -// String returns the usage -func (f IntSliceFlag) String() string { - firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") - pref := prefixFor(firstName) - return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f IntSliceFlag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - newVal := &IntSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - err := newVal.Set(s) - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &IntSlice{} - } - set.Var(f.Value, name, f.Usage) - }) -} - -func (f IntSliceFlag) GetName() string { - return f.Name -} - -// BoolFlag is a switch that defaults to false -type BoolFlag struct { - Name string - Usage string - EnvVar string - Destination *bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f BoolFlag) Apply(set *flag.FlagSet) { - val := false - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool - } - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) -} - -func (f BoolFlag) GetName() string { - return f.Name -} - -// BoolTFlag this represents a boolean flag that is true by default, but can -// still be set to false by --some-flag=false -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Destination *bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolTFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f BoolTFlag) Apply(set *flag.FlagSet) { - val := true - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool - break - } - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) -} - -func (f BoolTFlag) GetName() string { - return f.Name -} - -// StringFlag represents a flag that takes as string value -type StringFlag struct { - Name string - Value string - Usage string - EnvVar string - Destination *string -} - -// String returns the usage -func (f StringFlag) String() string { - var fmtString string - fmtString = "%s %v\t%v" - - if len(f.Value) > 0 { - fmtString = "%s \"%v\"\t%v" - } else { - fmtString = "%s %v\t%v" - } - - return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f StringFlag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - f.Value = envVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.StringVar(f.Destination, name, f.Value, f.Usage) - return - } - set.String(name, f.Value, f.Usage) - }) -} - -func (f StringFlag) GetName() string { - return f.Name -} - -// IntFlag is a flag that takes an integer -// Errors if the value provided cannot be parsed -type IntFlag struct { - Name string - Value int - Usage string - EnvVar string - Destination *int -} - -// String returns the usage -func (f IntFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f IntFlag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err == nil { - f.Value = int(envValInt) - break - } - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.IntVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Int(name, f.Value, f.Usage) - }) -} - -func (f IntFlag) GetName() string { - return f.Name -} - -// DurationFlag is a flag that takes a duration specified in Go's duration -// format: https://golang.org/pkg/time/#ParseDuration -type DurationFlag struct { - Name string - Value time.Duration - Usage string - EnvVar string - Destination *time.Duration -} - -// String returns a readable representation of this value (for usage defaults) -func (f DurationFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f DurationFlag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValDuration, err := time.ParseDuration(envVal) - if err == nil { - f.Value = envValDuration - break - } - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.DurationVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Duration(name, f.Value, f.Usage) - }) -} - -func (f DurationFlag) GetName() string { - return f.Name -} - -// Float64Flag is a flag that takes an float value -// Errors if the value provided cannot be parsed -type Float64Flag struct { - Name string - Value float64 - Usage string - EnvVar string - Destination *float64 -} - -// String returns the usage -func (f Float64Flag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) -} - -// Apply populates the flag given the flag set and environment -func (f Float64Flag) Apply(set *flag.FlagSet) { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValFloat, err := strconv.ParseFloat(envVal, 10) - if err == nil { - f.Value = float64(envValFloat) - } - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Float64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Float64(name, f.Value, f.Usage) - }) -} - -func (f Float64Flag) GetName() string { - return f.Name -} - -func prefixFor(name string) (prefix string) { - if len(name) == 1 { - prefix = "-" - } else { - prefix = "--" - } - - return -} - -func prefixedNames(fullName string) (prefixed string) { - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += prefixFor(name) + name - if i < len(parts)-1 { - prefixed += ", " - } - } - return -} - -func withEnvHint(envVar, str string) string { - envText := "" - if envVar != "" { - envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) - } - return str + envText -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/help.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/help.go deleted file mode 100644 index a246f63ac4d0da78d5f5d0bdf9357d6b55519603..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/codegangsta/cli/help.go +++ /dev/null @@ -1,246 +0,0 @@ -package cli - -import ( - "fmt" - "io" - "strings" - "text/tabwriter" - "text/template" -) - -// The text template for the Default help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var AppHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} - -USAGE: - {{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .Version}} -VERSION: - {{.Version}} - {{end}}{{if len .Authors}} -AUTHOR(S): - {{range .Authors}}{{ . }}{{end}} - {{end}}{{if .Commands}} -COMMANDS: - {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .Flags}} -GLOBAL OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{end}}{{if .Copyright }} -COPYRIGHT: - {{.Copyright}} - {{end}} -` - -// The text template for the command help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var CommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} - -USAGE: - {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if .Flags}} - -OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{ end }} -` - -// The text template for the subcommand help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} - -USAGE: - {{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - -COMMANDS: - {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{if .Flags}} -OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{end}} -` - -var helpCommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) { - args := c.Args() - if args.Present() { - ShowCommandHelp(c, args.First()) - } else { - ShowAppHelp(c) - } - }, -} - -var helpSubcommand = Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *Context) { - args := c.Args() - if args.Present() { - ShowCommandHelp(c, args.First()) - } else { - ShowSubcommandHelp(c) - } - }, -} - -// Prints help for the App or Command -type helpPrinter func(w io.Writer, templ string, data interface{}) - -var HelpPrinter helpPrinter = printHelp - -// Prints version for the App -var VersionPrinter = printVersion - -func ShowAppHelp(c *Context) { - HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) -} - -// Prints the list of subcommands as the default app completion method -func DefaultAppComplete(c *Context) { - for _, command := range c.App.Commands { - for _, name := range command.Names() { - fmt.Fprintln(c.App.Writer, name) - } - } -} - -// Prints help for the given command -func ShowCommandHelp(ctx *Context, command string) { - // show the subcommand help for a command with subcommands - if command == "" { - HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) - return - } - - for _, c := range ctx.App.Commands { - if c.HasName(command) { - HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) - return - } - } - - if ctx.App.CommandNotFound != nil { - ctx.App.CommandNotFound(ctx, command) - } else { - fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command) - } -} - -// Prints help for the given subcommand -func ShowSubcommandHelp(c *Context) { - ShowCommandHelp(c, c.Command.Name) -} - -// Prints the version number of the App -func ShowVersion(c *Context) { - VersionPrinter(c) -} - -func printVersion(c *Context) { - fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) -} - -// Prints the lists of commands within a given context -func ShowCompletions(c *Context) { - a := c.App - if a != nil && a.BashComplete != nil { - a.BashComplete(c) - } -} - -// Prints the custom completions for a given command -func ShowCommandCompletions(ctx *Context, command string) { - c := ctx.App.Command(command) - if c != nil && c.BashComplete != nil { - c.BashComplete(ctx) - } -} - -func printHelp(out io.Writer, templ string, data interface{}) { - funcMap := template.FuncMap{ - "join": strings.Join, - } - - w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0) - t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) - err := t.Execute(w, data) - if err != nil { - panic(err) - } - w.Flush() -} - -func checkVersion(c *Context) bool { - found := false - if VersionFlag.Name != "" { - eachName(VersionFlag.Name, func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkHelp(c *Context) bool { - found := false - if HelpFlag.Name != "" { - eachName(HelpFlag.Name, func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) - } - return found -} - -func checkCommandHelp(c *Context, name string) bool { - if c.Bool("h") || c.Bool("help") { - ShowCommandHelp(c, name) - return true - } - - return false -} - -func checkSubcommandHelp(c *Context) bool { - if c.GlobalBool("h") || c.GlobalBool("help") { - ShowSubcommandHelp(c) - return true - } - - return false -} - -func checkCompletions(c *Context) bool { - if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { - ShowCompletions(c) - return true - } - - return false -} - -func checkCommandCompletions(c *Context, name string) bool { - if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { - ShowCommandCompletions(c, name) - return true - } - - return false -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE deleted file mode 100644 index 37ec93a14fdcd0d6e525d97c0cfa6b314eaa98d8..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/files.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/files.go deleted file mode 100644 index c8e85fcd58894494b84693a9840e9c820558fce6..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/files.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package activation implements primitives for systemd socket activation. -package activation - -import ( - "os" - "strconv" - "syscall" -) - -// based on: https://gist.github.com/alberts/4640792 -const ( - listenFdsStart = 3 -) - -func Files(unsetEnv bool) []*os.File { - if unsetEnv { - defer os.Unsetenv("LISTEN_PID") - defer os.Unsetenv("LISTEN_FDS") - } - - pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) - if err != nil || pid != os.Getpid() { - return nil - } - - nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) - if err != nil || nfds == 0 { - return nil - } - - files := make([]*os.File, 0, nfds) - for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { - syscall.CloseOnExec(fd) - files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) - } - - return files -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/listeners.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/listeners.go deleted file mode 100644 index df27c29e9eaa8a19b090b713c7cdaab4300a589b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/listeners.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package activation - -import ( - "crypto/tls" - "net" -) - -// Listeners returns a slice containing a net.Listener for each matching socket type -// passed to this process. -// -// The order of the file descriptors is preserved in the returned slice. -// Nil values are used to fill any gaps. For example if systemd were to return file descriptors -// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener} -func Listeners(unsetEnv bool) ([]net.Listener, error) { - files := Files(unsetEnv) - listeners := make([]net.Listener, len(files)) - - for i, f := range files { - if pc, err := net.FileListener(f); err == nil { - listeners[i] = pc - } - } - return listeners, nil -} - -// TLSListeners returns a slice containing a net.listener for each matching TCP socket type -// passed to this process. -// It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig. -func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) { - listeners, err := Listeners(unsetEnv) - - if listeners == nil || err != nil { - return nil, err - } - - if tlsConfig != nil && err == nil { - tlsConfig.NextProtos = []string{"http/1.1"} - - for i, l := range listeners { - // Activate TLS only for TCP sockets - if l.Addr().Network() == "tcp" { - listeners[i] = tls.NewListener(l, tlsConfig) - } - } - } - - return listeners, err -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/packetconns.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/packetconns.go deleted file mode 100644 index 48b2ca029df208f20fd465f510a3c9a68e6eed75..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/activation/packetconns.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package activation - -import ( - "net" -) - -// PacketConns returns a slice containing a net.PacketConn for each matching socket type -// passed to this process. -// -// The order of the file descriptors is preserved in the returned slice. -// Nil values are used to fill any gaps. For example if systemd were to return file descriptors -// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn} -func PacketConns(unsetEnv bool) ([]net.PacketConn, error) { - files := Files(unsetEnv) - conns := make([]net.PacketConn, len(files)) - - for i, f := range files { - if pc, err := net.FilePacketConn(f); err == nil { - conns[i] = pc - } - } - return conns, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go deleted file mode 100644 index 5dd748e60ff142f6537e9a83d8b2ed0772939ce9..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/dbus.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ -package dbus - -import ( - "fmt" - "os" - "strconv" - "strings" - "sync" - - "github.com/godbus/dbus" -) - -const ( - alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` - num = `0123456789` - alphanum = alpha + num - signalBuffer = 100 -) - -// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped -func needsEscape(i int, b byte) bool { - // Escape everything that is not a-z-A-Z-0-9 - // Also escape 0-9 if it's the first character - return strings.IndexByte(alphanum, b) == -1 || - (i == 0 && strings.IndexByte(num, b) != -1) -} - -// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the -// rules that systemd uses for serializing special characters. -func PathBusEscape(path string) string { - // Special case the empty string - if len(path) == 0 { - return "_" - } - n := []byte{} - for i := 0; i < len(path); i++ { - c := path[i] - if needsEscape(i, c) { - e := fmt.Sprintf("_%x", c) - n = append(n, []byte(e)...) - } else { - n = append(n, c) - } - } - return string(n) -} - -// Conn is a connection to systemd's dbus endpoint. -type Conn struct { - // sysconn/sysobj are only used to call dbus methods - sysconn *dbus.Conn - sysobj dbus.BusObject - - // sigconn/sigobj are only used to receive dbus signals - sigconn *dbus.Conn - sigobj dbus.BusObject - - jobListener struct { - jobs map[dbus.ObjectPath]chan<- string - sync.Mutex - } - subscriber struct { - updateCh chan<- *SubStateUpdate - errCh chan<- error - sync.Mutex - ignore map[dbus.ObjectPath]int64 - cleanIgnore int64 - } -} - -// New establishes a connection to the system bus and authenticates. -// Callers should call Close() when done with the connection. -func New() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SystemBusPrivate) - }) -} - -// NewUserConnection establishes a connection to the session bus and -// authenticates. This can be used to connect to systemd user instances. -// Callers should call Close() when done with the connection. -func NewUserConnection() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SessionBusPrivate) - }) -} - -// NewSystemdConnection establishes a private, direct connection to systemd. -// This can be used for communicating with systemd without a dbus daemon. -// Callers should call Close() when done with the connection. -func NewSystemdConnection() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { - // We skip Hello when talking directly to systemd. - return dbusAuthConnection(func() (*dbus.Conn, error) { - return dbus.Dial("unix:path=/run/systemd/private") - }) - }) -} - -// Close closes an established connection -func (c *Conn) Close() { - c.sysconn.Close() - c.sigconn.Close() -} - -func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := createBus() - if err != nil { - return nil, err - } - - sigconn, err := createBus() - if err != nil { - sysconn.Close() - return nil, err - } - - c := &Conn{ - sysconn: sysconn, - sysobj: systemdObject(sysconn), - sigconn: sigconn, - sigobj: systemdObject(sigconn), - } - - c.subscriber.ignore = make(map[dbus.ObjectPath]int64) - c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) - - // Setup the listeners on jobs so that we can get completions - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") - - c.dispatch() - return c, nil -} - -func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := createBus() - if err != nil { - return nil, err - } - - // Only use EXTERNAL method, and hardcode the uid (not username) - // to avoid a username lookup (which requires a dynamically linked - // libc) - methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))} - - err = conn.Auth(methods) - if err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := dbusAuthConnection(createBus) - if err != nil { - return nil, err - } - - if err = conn.Hello(); err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func systemdObject(conn *dbus.Conn) dbus.BusObject { - return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods.go deleted file mode 100644 index ab614c7c63924086625f9f8b55a4c3f0053979a9..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/methods.go +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "errors" - "path" - "strconv" - - "github.com/godbus/dbus" -) - -func (c *Conn) jobComplete(signal *dbus.Signal) { - var id uint32 - var job dbus.ObjectPath - var unit string - var result string - dbus.Store(signal.Body, &id, &job, &unit, &result) - c.jobListener.Lock() - out, ok := c.jobListener.jobs[job] - if ok { - out <- result - delete(c.jobListener.jobs, job) - } - c.jobListener.Unlock() -} - -func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { - if ch != nil { - c.jobListener.Lock() - defer c.jobListener.Unlock() - } - - var p dbus.ObjectPath - err := c.sysobj.Call(job, 0, args...).Store(&p) - if err != nil { - return 0, err - } - - if ch != nil { - c.jobListener.jobs[p] = ch - } - - // ignore error since 0 is fine if conversion fails - jobID, _ := strconv.Atoi(path.Base(string(p))) - - return jobID, nil -} - -// StartUnit enqueues a start job and depending jobs, if any (unless otherwise -// specified by the mode string). -// -// Takes the unit to activate, plus a mode string. The mode needs to be one of -// replace, fail, isolate, ignore-dependencies, ignore-requirements. If -// "replace" the call will start the unit and its dependencies, possibly -// replacing already queued jobs that conflict with this. If "fail" the call -// will start the unit and its dependencies, but will fail if this would change -// an already queued job. If "isolate" the call will start the unit in question -// and terminate all units that aren't dependencies of it. If -// "ignore-dependencies" it will start a unit but ignore all its dependencies. -// If "ignore-requirements" it will start a unit but only ignore the -// requirement dependencies. It is not recommended to make use of the latter -// two options. -// -// If the provided channel is non-nil, a result string will be sent to it upon -// job completion: one of done, canceled, timeout, failed, dependency, skipped. -// done indicates successful execution of a job. canceled indicates that a job -// has been canceled before it finished execution. timeout indicates that the -// job timeout was reached. failed indicates that the job failed. dependency -// indicates that a job this job has been depending on failed and the job hence -// has been removed too. skipped indicates that a job was skipped because it -// didn't apply to the units current state. -// -// If no error occurs, the ID of the underlying systemd job will be returned. There -// does exist the possibility for no error to be returned, but for the returned job -// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint -// should not be considered authoritative. -// -// If an error does occur, it will be returned to the user alongside a job ID of 0. -func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) -} - -// StopUnit is similar to StartUnit but stops the specified unit rather -// than starting it. -func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) -} - -// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. -func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) -} - -// RestartUnit restarts a service. If a service is restarted that isn't -// running it will be started. -func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) -} - -// TryRestartUnit is like RestartUnit, except that a service that isn't running -// is not affected by the restart. -func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) -} - -// ReloadOrRestart attempts a reload if the unit supports it and use a restart -// otherwise. -func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) -} - -// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" -// flavored restart otherwise. -func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) -} - -// StartTransientUnit() may be used to create and start a transient unit, which -// will be released as soon as it is not running or referenced anymore or the -// system is rebooted. name is the unit name including suffix, and must be -// unique. mode is the same as in StartUnit(), properties contains properties -// of the unit. -func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) -} - -// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's -// processes are killed. -func (c *Conn) KillUnit(name string, signal int32) { - c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() -} - -// ResetFailedUnit resets the "failed" state of a specific unit. -func (c *Conn) ResetFailedUnit(name string) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() -} - -// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface -func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) { - var err error - var props map[string]dbus.Variant - - path := unitPath(unit) - if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) - if err != nil { - return nil, err - } - - out := make(map[string]interface{}, len(props)) - for k, v := range props { - out[k] = v.Value() - } - - return out, nil -} - -// GetUnitProperties takes the unit name and returns all of its dbus object properties. -func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1.Unit") -} - -func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { - var err error - var prop dbus.Variant - - path := unitPath(unit) - if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) - if err != nil { - return nil, err - } - - return &Property{Name: propertyName, Value: prop}, nil -} - -func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) -} - -// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. -// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope -// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit -func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1."+unitType) -} - -// SetUnitProperties() may be used to modify certain unit properties at runtime. -// Not all properties may be changed at runtime, but many resource management -// settings (primarily those in systemd.cgroup(5)) may. The changes are applied -// instantly, and stored on disk for future boots, unless runtime is true, in which -// case the settings only apply until the next reboot. name is the name of the unit -// to modify. properties are the settings to set, encoded as an array of property -// name and value pairs. -func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() -} - -func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) -} - -// ListUnits returns an array with all currently loaded units. Note that -// units may be known by multiple names at the same time, and hence there might -// be more unit names loaded than actual units behind them. -func (c *Conn) ListUnits() ([]UnitStatus, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - status := make([]UnitStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } - - err = dbus.Store(resultInterface, statusInterface...) - if err != nil { - return nil, err - } - - return status, nil -} - -type UnitStatus struct { - Name string // The primary unit name as string - Description string // The human readable description string - LoadState string // The load state (i.e. whether the unit file has been loaded successfully) - ActiveState string // The active state (i.e. whether the unit is currently started or not) - SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not) - Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string. - Path dbus.ObjectPath // The unit object path - JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise - JobType string // The job type as string - JobPath dbus.ObjectPath // The job object path -} - -type LinkUnitFileChange EnableUnitFileChange - -// LinkUnitFiles() links unit files (that are located outside of the -// usual unit search paths) into the unit search path. -// -// It takes a list of absolute paths to unit files to link and two -// booleans. The first boolean controls whether the unit shall be -// enabled for runtime only (true, /run), or persistently (false, -// /etc). -// The second controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns a list of the changes made. The list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]LinkUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -// EnableUnitFiles() may be used to enable one or more units in the system (by -// creating symlinks to them in /etc or /run). -// -// It takes a list of unit files to enable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and two booleans: the first controls whether the unit shall -// be enabled for runtime only (true, /run), or persistently (false, /etc). -// The second one controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns one boolean and an array with the changes made. The -// boolean signals whether the unit files contained any enablement -// information (i.e. an [Install]) section. The changes list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { - var carries_install_info bool - - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) - if err != nil { - return false, nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]EnableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return false, nil, err - } - - return carries_install_info, changes, nil -} - -type EnableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// DisableUnitFiles() may be used to disable one or more units in the system (by -// removing symlinks to them from /etc or /run). -// -// It takes a list of unit files to disable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and one boolean: whether the unit was enabled for runtime -// only (true, /run), or persistently (false, /etc). -// -// This call returns an array with the changes made. The changes list -// consists of structures with three strings: the type of the change (one of -// symlink or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]DisableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type DisableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Reload instructs systemd to scan for and reload unit files. This is -// equivalent to a 'systemctl daemon-reload'. -func (c *Conn) Reload() error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() -} - -func unitPath(name string) dbus.ObjectPath { - return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/properties.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/properties.go deleted file mode 100644 index 7520011564e1e469877000a20f29770d40491d31..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/properties.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "github.com/godbus/dbus" -) - -// From the systemd docs: -// -// The properties array of StartTransientUnit() may take many of the settings -// that may also be configured in unit files. Not all parameters are currently -// accepted though, but we plan to cover more properties with future release. -// Currently you may set the Description, Slice and all dependency types of -// units, as well as RemainAfterExit, ExecStart for service units, -// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares, -// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth, -// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit, -// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map -// directly to their counterparts in unit files and as normal D-Bus object -// properties. The exception here is the PIDs field of scope units which is -// used for construction of the scope only and specifies the initial PIDs to -// add to the scope object. - -type Property struct { - Name string - Value dbus.Variant -} - -type PropertyCollection struct { - Name string - Properties []Property -} - -type execStart struct { - Path string // the binary path to execute - Args []string // an array with all arguments to pass to the executed command, starting with argument 0 - UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly -} - -// PropExecStart sets the ExecStart service property. The first argument is a -// slice with the binary path to execute followed by the arguments to pass to -// the executed command. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= -func PropExecStart(command []string, uncleanIsFailure bool) Property { - execStarts := []execStart{ - execStart{ - Path: command[0], - Args: command, - UncleanIsFailure: uncleanIsFailure, - }, - } - - return Property{ - Name: "ExecStart", - Value: dbus.MakeVariant(execStarts), - } -} - -// PropRemainAfterExit sets the RemainAfterExit service property. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit= -func PropRemainAfterExit(b bool) Property { - return Property{ - Name: "RemainAfterExit", - Value: dbus.MakeVariant(b), - } -} - -// PropDescription sets the Description unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description= -func PropDescription(desc string) Property { - return Property{ - Name: "Description", - Value: dbus.MakeVariant(desc), - } -} - -func propDependency(name string, units []string) Property { - return Property{ - Name: name, - Value: dbus.MakeVariant(units), - } -} - -// PropRequires sets the Requires unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires= -func PropRequires(units ...string) Property { - return propDependency("Requires", units) -} - -// PropRequiresOverridable sets the RequiresOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable= -func PropRequiresOverridable(units ...string) Property { - return propDependency("RequiresOverridable", units) -} - -// PropRequisite sets the Requisite unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite= -func PropRequisite(units ...string) Property { - return propDependency("Requisite", units) -} - -// PropRequisiteOverridable sets the RequisiteOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable= -func PropRequisiteOverridable(units ...string) Property { - return propDependency("RequisiteOverridable", units) -} - -// PropWants sets the Wants unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants= -func PropWants(units ...string) Property { - return propDependency("Wants", units) -} - -// PropBindsTo sets the BindsTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo= -func PropBindsTo(units ...string) Property { - return propDependency("BindsTo", units) -} - -// PropRequiredBy sets the RequiredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy= -func PropRequiredBy(units ...string) Property { - return propDependency("RequiredBy", units) -} - -// PropRequiredByOverridable sets the RequiredByOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable= -func PropRequiredByOverridable(units ...string) Property { - return propDependency("RequiredByOverridable", units) -} - -// PropWantedBy sets the WantedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy= -func PropWantedBy(units ...string) Property { - return propDependency("WantedBy", units) -} - -// PropBoundBy sets the BoundBy unit property. See -// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy= -func PropBoundBy(units ...string) Property { - return propDependency("BoundBy", units) -} - -// PropConflicts sets the Conflicts unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts= -func PropConflicts(units ...string) Property { - return propDependency("Conflicts", units) -} - -// PropConflictedBy sets the ConflictedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy= -func PropConflictedBy(units ...string) Property { - return propDependency("ConflictedBy", units) -} - -// PropBefore sets the Before unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before= -func PropBefore(units ...string) Property { - return propDependency("Before", units) -} - -// PropAfter sets the After unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After= -func PropAfter(units ...string) Property { - return propDependency("After", units) -} - -// PropOnFailure sets the OnFailure unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure= -func PropOnFailure(units ...string) Property { - return propDependency("OnFailure", units) -} - -// PropTriggers sets the Triggers unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers= -func PropTriggers(units ...string) Property { - return propDependency("Triggers", units) -} - -// PropTriggeredBy sets the TriggeredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy= -func PropTriggeredBy(units ...string) Property { - return propDependency("TriggeredBy", units) -} - -// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo= -func PropPropagatesReloadTo(units ...string) Property { - return propDependency("PropagatesReloadTo", units) -} - -// PropRequiresMountsFor sets the RequiresMountsFor unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor= -func PropRequiresMountsFor(units ...string) Property { - return propDependency("RequiresMountsFor", units) -} - -// PropSlice sets the Slice unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice= -func PropSlice(slice string) Property { - return Property{ - Name: "Slice", - Value: dbus.MakeVariant(slice), - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set.go deleted file mode 100644 index f92e6fbed1eaa86a1a0f92759ce3132881c29913..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/set.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -type set struct { - data map[string]bool -} - -func (s *set) Add(value string) { - s.data[value] = true -} - -func (s *set) Remove(value string) { - delete(s.data, value) -} - -func (s *set) Contains(value string) (exists bool) { - _, exists = s.data[value] - return -} - -func (s *set) Length() int { - return len(s.data) -} - -func (s *set) Values() (values []string) { - for val, _ := range s.data { - values = append(values, val) - } - return -} - -func newSet() *set { - return &set{make(map[string]bool)} -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription.go deleted file mode 100644 index 996451445c06e66ecfe7f15af8771e6ad8e515b7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "errors" - "time" - - "github.com/godbus/dbus" -) - -const ( - cleanIgnoreInterval = int64(10 * time.Second) - ignoreInterval = int64(30 * time.Millisecond) -) - -// Subscribe sets up this connection to subscribe to all systemd dbus events. -// This is required before calling SubscribeUnits. When the connection closes -// systemd will automatically stop sending signals so there is no need to -// explicitly call Unsubscribe(). -func (c *Conn) Subscribe() error { - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") - - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() - if err != nil { - return err - } - - return nil -} - -// Unsubscribe this connection from systemd dbus events. -func (c *Conn) Unsubscribe() error { - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() - if err != nil { - return err - } - - return nil -} - -func (c *Conn) dispatch() { - ch := make(chan *dbus.Signal, signalBuffer) - - c.sigconn.Signal(ch) - - go func() { - for { - signal, ok := <-ch - if !ok { - return - } - - if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" { - c.jobComplete(signal) - } - - if c.subscriber.updateCh == nil { - continue - } - - var unitPath dbus.ObjectPath - switch signal.Name { - case "org.freedesktop.systemd1.Manager.JobRemoved": - unitName := signal.Body[2].(string) - c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) - case "org.freedesktop.systemd1.Manager.UnitNew": - unitPath = signal.Body[1].(dbus.ObjectPath) - case "org.freedesktop.DBus.Properties.PropertiesChanged": - if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { - unitPath = signal.Path - } - } - - if unitPath == dbus.ObjectPath("") { - continue - } - - c.sendSubStateUpdate(unitPath) - } - }() -} - -// Returns two unbuffered channels which will receive all changed units every -// interval. Deleted units are sent as nil. -func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { - return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) -} - -// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer -// size of the channels, the comparison function for detecting changes and a filter -// function for cutting down on the noise that your channel receives. -func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { - old := make(map[string]*UnitStatus) - statusChan := make(chan map[string]*UnitStatus, buffer) - errChan := make(chan error, buffer) - - go func() { - for { - timerChan := time.After(interval) - - units, err := c.ListUnits() - if err == nil { - cur := make(map[string]*UnitStatus) - for i := range units { - if filterUnit != nil && filterUnit(units[i].Name) { - continue - } - cur[units[i].Name] = &units[i] - } - - // add all new or changed units - changed := make(map[string]*UnitStatus) - for n, u := range cur { - if oldU, ok := old[n]; !ok || isChanged(oldU, u) { - changed[n] = u - } - delete(old, n) - } - - // add all deleted units - for oldN := range old { - changed[oldN] = nil - } - - old = cur - - if len(changed) != 0 { - statusChan <- changed - } - } else { - errChan <- err - } - - <-timerChan - } - }() - - return statusChan, errChan -} - -type SubStateUpdate struct { - UnitName string - SubState string -} - -// SetSubStateSubscriber writes to updateCh when any unit's substate changes. -// Although this writes to updateCh on every state change, the reported state -// may be more recent than the change that generated it (due to an unavoidable -// race in the systemd dbus interface). That is, this method provides a good -// way to keep a current view of all units' states, but is not guaranteed to -// show every state transition they go through. Furthermore, state changes -// will only be written to the channel with non-blocking writes. If updateCh -// is full, it attempts to write an error to errCh; if errCh is full, the error -// passes silently. -func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { - c.subscriber.Lock() - defer c.subscriber.Unlock() - c.subscriber.updateCh = updateCh - c.subscriber.errCh = errCh -} - -func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { - c.subscriber.Lock() - defer c.subscriber.Unlock() - - if c.shouldIgnore(path) { - return - } - - info, err := c.GetUnitProperties(string(path)) - if err != nil { - select { - case c.subscriber.errCh <- err: - default: - } - } - - name := info["Id"].(string) - substate := info["SubState"].(string) - - update := &SubStateUpdate{name, substate} - select { - case c.subscriber.updateCh <- update: - default: - select { - case c.subscriber.errCh <- errors.New("update channel full!"): - default: - } - } - - c.updateIgnore(path, info) -} - -// The ignore functions work around a wart in the systemd dbus interface. -// Requesting the properties of an unloaded unit will cause systemd to send a -// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's -// properties on UnitNew (as that's the only indication of a new unit coming up -// for the first time), we would enter an infinite loop if we did not attempt -// to detect and ignore these spurious signals. The signal themselves are -// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an -// unloaded unit's signals for a short time after requesting its properties. -// This means that we will miss e.g. a transient unit being restarted -// *immediately* upon failure and also a transient unit being started -// immediately after requesting its status (with systemctl status, for example, -// because this causes a UnitNew signal to be sent which then causes us to fetch -// the properties). - -func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { - t, ok := c.subscriber.ignore[path] - return ok && t >= time.Now().UnixNano() -} - -func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { - c.cleanIgnore() - - // unit is unloaded - it will trigger bad systemd dbus behavior - if info["LoadState"].(string) == "not-found" { - c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval - } -} - -// without this, ignore would grow unboundedly over time -func (c *Conn) cleanIgnore() { - now := time.Now().UnixNano() - if c.subscriber.cleanIgnore < now { - c.subscriber.cleanIgnore = now + cleanIgnoreInterval - - for p, t := range c.subscriber.ignore { - if t < now { - delete(c.subscriber.ignore, p) - } - } - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set.go deleted file mode 100644 index 5b408d5847ad5309754ae69ed5fa69c9f8a391d7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus/subscription_set.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "time" -) - -// SubscriptionSet returns a subscription set which is like conn.Subscribe but -// can filter to only return events for a set of units. -type SubscriptionSet struct { - *set - conn *Conn -} - -func (s *SubscriptionSet) filter(unit string) bool { - return !s.Contains(unit) -} - -// Subscribe starts listening for dbus events for all of the units in the set. -// Returns channels identical to conn.SubscribeUnits. -func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { - // TODO: Make fully evented by using systemd 209 with properties changed values - return s.conn.SubscribeUnitsCustom(time.Second, 0, - mismatchUnitStatus, - func(unit string) bool { return s.filter(unit) }, - ) -} - -// NewSubscriptionSet returns a new subscription set. -func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { - return &SubscriptionSet{newSet(), conn} -} - -// mismatchUnitStatus returns true if the provided UnitStatus objects -// are not equivalent. false is returned if the objects are equivalent. -// Only the Name, Description and state-related fields are used in -// the comparison. -func mismatchUnitStatus(u1, u2 *UnitStatus) bool { - return u1.Name != u2.Name || - u1.Description != u2.Description || - u1.LoadState != u2.LoadState || - u1.ActiveState != u2.ActiveState || - u1.SubState != u2.SubState -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/util/util.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/util/util.go deleted file mode 100644 index 33832a1ed436da85767953523efd11c79113f4b2..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/coreos/go-systemd/util/util.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package util contains utility functions related to systemd that applications -// can use to check things like whether systemd is running. -package util - -import ( - "os" -) - -// IsRunningSystemd checks whether the host was booted with systemd as its init -// system. This functions similar to systemd's `sd_booted(3)`: internally, it -// checks whether /run/systemd/system/ exists and is a directory. -// http://www.freedesktop.org/software/systemd/man/sd_booted.html -func IsRunningSystemd() bool { - fi, err := os.Lstat("/run/systemd/system") - if err != nil { - return false - } - return fi.IsDir() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/LICENSE deleted file mode 100644 index c7a3f0cfd4562c0a99091050ae17a33878af9d20..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2013-2015 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/NOTICE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/NOTICE deleted file mode 100644 index 6e6f469ab9b280ff337ae8a074884a2eca44cc8b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/NOTICE +++ /dev/null @@ -1,19 +0,0 @@ -Docker -Copyright 2012-2015 Docker, Inc. - -This product includes software developed at Docker, Inc. (https://www.docker.com). - -This product contains software (https://github.com/kr/pty) developed -by Keith Rarick, licensed under the MIT License. - -The following is courtesy of our legal counsel: - - -Use and transfer of Docker may be subject to certain restrictions by the -United States and other governments. -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see https://www.bis.doc.gov - -See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/contrib/syntax/vim/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/contrib/syntax/vim/LICENSE deleted file mode 100644 index e67cdabd22e5fe01f016512e726b87d6243a419b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/contrib/syntax/vim/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Honza Pokorny -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/docs/project/images/red_notice.png b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/docs/project/images/red_notice.png deleted file mode 100644 index 8839723a376b4a58ef31b86eabf3d2c57d21ccc3..0000000000000000000000000000000000000000 Binary files a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/docs/project/images/red_notice.png and /dev/null differ diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE deleted file mode 100644 index ac74d8f0496ca170fe1529bebfb983468ce989da..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mflag/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014-2015 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go deleted file mode 100644 index 17dbd7a64cf4f4ae15cbcc0038eab358849f3de4..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags.go +++ /dev/null @@ -1,69 +0,0 @@ -package mount - -import ( - "strings" -) - -// Parse fstab type mount options into mount() flags -// and device specific data -func parseOptions(options string) (int, string) { - var ( - flag int - data []string - ) - - flags := map[string]struct { - clear bool - flag int - }{ - "defaults": {false, 0}, - "ro": {false, RDONLY}, - "rw": {true, RDONLY}, - "suid": {true, NOSUID}, - "nosuid": {false, NOSUID}, - "dev": {true, NODEV}, - "nodev": {false, NODEV}, - "exec": {true, NOEXEC}, - "noexec": {false, NOEXEC}, - "sync": {false, SYNCHRONOUS}, - "async": {true, SYNCHRONOUS}, - "dirsync": {false, DIRSYNC}, - "remount": {false, REMOUNT}, - "mand": {false, MANDLOCK}, - "nomand": {true, MANDLOCK}, - "atime": {true, NOATIME}, - "noatime": {false, NOATIME}, - "diratime": {true, NODIRATIME}, - "nodiratime": {false, NODIRATIME}, - "bind": {false, BIND}, - "rbind": {false, RBIND}, - "unbindable": {false, UNBINDABLE}, - "runbindable": {false, RUNBINDABLE}, - "private": {false, PRIVATE}, - "rprivate": {false, RPRIVATE}, - "shared": {false, SHARED}, - "rshared": {false, RSHARED}, - "slave": {false, SLAVE}, - "rslave": {false, RSLAVE}, - "relatime": {false, RELATIME}, - "norelatime": {true, RELATIME}, - "strictatime": {false, STRICTATIME}, - "nostrictatime": {true, STRICTATIME}, - } - - for _, o := range strings.Split(options, ",") { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else { - data = append(data, o) - } - } - return flag, strings.Join(data, ",") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_freebsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_freebsd.go deleted file mode 100644 index f166cb2f77864fec5a9be945a2264e783585fd59..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_freebsd.go +++ /dev/null @@ -1,48 +0,0 @@ -// +build freebsd,cgo - -package mount - -/* -#include <sys/mount.h> -*/ -import "C" - -const ( - // RDONLY will mount the filesystem as read-only. - RDONLY = C.MNT_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = C.MNT_NOSUID - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = C.MNT_NOEXEC - - // SYNCHRONOUS will allow any I/O to the file system to be done synchronously. - SYNCHRONOUS = C.MNT_SYNCHRONOUS - - // NOATIME will not update the file access time when reading from a file. - NOATIME = C.MNT_NOATIME -) - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NODEV = 0 - NODIRATIME = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIVE = 0 - RELATIME = 0 - REMOUNT = 0 - STRICTATIME = 0 -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_linux.go deleted file mode 100644 index 2f9f5c58ee5d849e1ecd74eb77e4c16079503bc2..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_linux.go +++ /dev/null @@ -1,85 +0,0 @@ -package mount - -import ( - "syscall" -) - -const ( - // RDONLY will mount the file system read-only. - RDONLY = syscall.MS_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = syscall.MS_NOSUID - - // NODEV will not interpret character or block special devices on the file - // system. - NODEV = syscall.MS_NODEV - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = syscall.MS_NOEXEC - - // SYNCHRONOUS will allow I/O to the file system to be done synchronously. - SYNCHRONOUS = syscall.MS_SYNCHRONOUS - - // DIRSYNC will force all directory updates within the file system to be done - // synchronously. This affects the following system calls: creat, link, - // unlink, symlink, mkdir, rmdir, mknod and rename. - DIRSYNC = syscall.MS_DIRSYNC - - // REMOUNT will attempt to remount an already-mounted file system. This is - // commonly used to change the mount flags for a file system, especially to - // make a readonly file system writeable. It does not change device or mount - // point. - REMOUNT = syscall.MS_REMOUNT - - // MANDLOCK will force mandatory locks on a filesystem. - MANDLOCK = syscall.MS_MANDLOCK - - // NOATIME will not update the file access time when reading from a file. - NOATIME = syscall.MS_NOATIME - - // NODIRATIME will not update the directory access time. - NODIRATIME = syscall.MS_NODIRATIME - - // BIND remounts a subtree somewhere else. - BIND = syscall.MS_BIND - - // RBIND remounts a subtree and all possible submounts somewhere else. - RBIND = syscall.MS_BIND | syscall.MS_REC - - // UNBINDABLE creates a mount which cannot be cloned through a bind operation. - UNBINDABLE = syscall.MS_UNBINDABLE - - // RUNBINDABLE marks the entire mount tree as UNBINDABLE. - RUNBINDABLE = syscall.MS_UNBINDABLE | syscall.MS_REC - - // PRIVATE creates a mount which carries no propagation abilities. - PRIVATE = syscall.MS_PRIVATE - - // RPRIVATE marks the entire mount tree as PRIVATE. - RPRIVATE = syscall.MS_PRIVATE | syscall.MS_REC - - // SLAVE creates a mount which receives propagation from its master, but not - // vice versa. - SLAVE = syscall.MS_SLAVE - - // RSLAVE marks the entire mount tree as SLAVE. - RSLAVE = syscall.MS_SLAVE | syscall.MS_REC - - // SHARED creates a mount which provides the ability to create mirrors of - // that mount such that mounts and unmounts within any of the mirrors - // propagate to the other mirrors. - SHARED = syscall.MS_SHARED - - // RSHARED marks the entire mount tree as SHARED. - RSHARED = syscall.MS_SHARED | syscall.MS_REC - - // RELATIME updates inode access times relative to modify or change time. - RELATIME = syscall.MS_RELATIME - - // STRICTATIME allows to explicitly request full atime updates. This makes - // it possible for the kernel to default to relatime or noatime but still - // allow userspace to override it. - STRICTATIME = syscall.MS_STRICTATIME -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go deleted file mode 100644 index a90d3d1151263bcb8f56e5ea235326cf81de90e3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/flags_unsupported.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !linux,!freebsd freebsd,!cgo - -package mount - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NOATIME = 0 - NODEV = 0 - NODIRATIME = 0 - NOEXEC = 0 - NOSUID = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIME = 0 - RELATIVE = 0 - REMOUNT = 0 - STRICTATIME = 0 - SYNCHRONOUS = 0 - RDONLY = 0 -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go deleted file mode 100644 index ed7216e5c04da8b39302a2c30afc1b6c5bef2d46..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mount.go +++ /dev/null @@ -1,74 +0,0 @@ -package mount - -import ( - "time" -) - -// GetMounts retrieves a list of mounts for the current running process. -func GetMounts() ([]*Info, error) { - return parseMountTable() -} - -// Mounted looks at /proc/self/mountinfo to determine of the specified -// mountpoint has been mounted -func Mounted(mountpoint string) (bool, error) { - entries, err := parseMountTable() - if err != nil { - return false, err - } - - // Search the table for the mountpoint - for _, e := range entries { - if e.Mountpoint == mountpoint { - return true, nil - } - } - return false, nil -} - -// Mount will mount filesystem according to the specified configuration, on the -// condition that the target path is *not* already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func Mount(device, target, mType, options string) error { - flag, _ := parseOptions(options) - if flag&REMOUNT != REMOUNT { - if mounted, err := Mounted(target); err != nil || mounted { - return err - } - } - return ForceMount(device, target, mType, options) -} - -// ForceMount will mount a filesystem according to the specified configuration, -// *regardless* if the target path is not already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func ForceMount(device, target, mType, options string) error { - flag, data := parseOptions(options) - if err := mount(device, target, mType, uintptr(flag), data); err != nil { - return err - } - return nil -} - -// Unmount will unmount the target filesystem, so long as it is mounted. -func Unmount(target string) error { - if mounted, err := Mounted(target); err != nil || !mounted { - return err - } - return ForceUnmount(target) -} - -// ForceUnmount will force an unmount of the target filesystem, regardless if -// it is mounted or not. -func ForceUnmount(target string) (err error) { - // Simple retry logic for unmount - for i := 0; i < 10; i++ { - if err = unmount(target, 0); err == nil { - return nil - } - time.Sleep(100 * time.Millisecond) - } - return -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_freebsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_freebsd.go deleted file mode 100644 index bb870e6f59b9f2dcd50cf9469b6c7edb11dab281..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_freebsd.go +++ /dev/null @@ -1,59 +0,0 @@ -package mount - -/* -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <sys/_iovec.h> -#include <sys/mount.h> -#include <sys/param.h> -*/ -import "C" - -import ( - "fmt" - "strings" - "syscall" - "unsafe" -) - -func allocateIOVecs(options []string) []C.struct_iovec { - out := make([]C.struct_iovec, len(options)) - for i, option := range options { - out[i].iov_base = unsafe.Pointer(C.CString(option)) - out[i].iov_len = C.size_t(len(option) + 1) - } - return out -} - -func mount(device, target, mType string, flag uintptr, data string) error { - isNullFS := false - - xs := strings.Split(data, ",") - for _, x := range xs { - if x == "bind" { - isNullFS = true - } - } - - options := []string{"fspath", target} - if isNullFS { - options = append(options, "fstype", "nullfs", "target", device) - } else { - options = append(options, "fstype", mType, "from", device) - } - rawOptions := allocateIOVecs(options) - for _, rawOption := range rawOptions { - defer C.free(rawOption.iov_base) - } - - if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { - reason := C.GoString(C.strerror(*C.__error())) - return fmt.Errorf("Failed to call nmount: %s", reason) - } - return nil -} - -func unmount(target string, flag int) error { - return syscall.Unmount(target, flag) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_linux.go deleted file mode 100644 index dd4280c7778626251ca049f66d18e4d8409ebda2..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -package mount - -import ( - "syscall" -) - -func mount(device, target, mType string, flag uintptr, data string) error { - if err := syscall.Mount(device, target, mType, flag, data); err != nil { - return err - } - - // If we have a bind mount or remount, remount... - if flag&syscall.MS_BIND == syscall.MS_BIND && flag&syscall.MS_RDONLY == syscall.MS_RDONLY { - return syscall.Mount(device, target, mType, flag|syscall.MS_REMOUNT, data) - } - return nil -} - -func unmount(target string, flag int) error { - return syscall.Unmount(target, flag) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go deleted file mode 100644 index eb93365eb74311e59439b44c302594448dc19075..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !linux,!freebsd freebsd,!cgo - -package mount - -func mount(device, target, mType string, flag uintptr, data string) error { - panic("Not implemented") -} - -func unmount(target string, flag int) error { - panic("Not implemented") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go deleted file mode 100644 index 4f32edcd906adda8167e746d4ed762ff61a487c6..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go +++ /dev/null @@ -1,41 +0,0 @@ -package mount - -/* -#include <sys/param.h> -#include <sys/ucred.h> -#include <sys/mount.h> -*/ -import "C" - -import ( - "fmt" - "reflect" - "unsafe" -) - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from -// bind mounts. -func parseMountTable() ([]*Info, error) { - var rawEntries *C.struct_statfs - - count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) - if count == 0 { - return nil, fmt.Errorf("Failed to call getmntinfo") - } - - var entries []C.struct_statfs - header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) - header.Cap = count - header.Len = count - header.Data = uintptr(unsafe.Pointer(rawEntries)) - - var out []*Info - for _, entry := range entries { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) - mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) - mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) - out = append(out, &mountinfo) - } - return out, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go deleted file mode 100644 index 8245f01d42bc2b5c36c270d219c30b6aa338ea39..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !linux,!freebsd freebsd,!cgo - -package mount - -import ( - "fmt" - "runtime" -) - -func parseMountTable() ([]*Info, error) { - return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go deleted file mode 100644 index 47303bbcb610da9a5a4be65196a9551459ab6176..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go +++ /dev/null @@ -1,70 +0,0 @@ -// +build linux - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - mounted, err := Mounted(mountPoint) - if err != nil { - return err - } - - if !mounted { - if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { - return err - } - } - mounted, err = Mounted(mountPoint) - if err != nil { - return err - } - - return ForceMount("", mountPoint, "none", options) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE deleted file mode 100644 index 9e4bd4dbee94d6801a7e07f12ad320e87386c212..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.APACHE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2014-2015 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD deleted file mode 100644 index ac74d8f0496ca170fe1529bebfb983468ce989da..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/LICENSE.BSD +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014-2015 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go deleted file mode 100644 index b4bdff24dd390ed16207df9225710dd62b4d313e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/symlink/fs.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.BSD file. - -// This code is a modified version of path/filepath/symlink.go from the Go standard library. - -package symlink - -import ( - "bytes" - "errors" - "os" - "path/filepath" - "strings" -) - -// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an absolute path -func FollowSymlinkInScope(path, root string) (string, error) { - path, err := filepath.Abs(path) - if err != nil { - return "", err - } - root, err = filepath.Abs(root) - if err != nil { - return "", err - } - return evalSymlinksInScope(path, root) -} - -// evalSymlinksInScope will evaluate symlinks in `path` within a scope `root` and return -// a result guaranteed to be contained within the scope `root`, at the time of the call. -// Symlinks in `root` are not evaluated and left as-is. -// Errors encountered while attempting to evaluate symlinks in path will be returned. -// Non-existing paths are valid and do not constitute an error. -// `path` has to contain `root` as a prefix, or else an error will be returned. -// Trying to break out from `root` does not constitute an error. -// -// Example: -// If /foo/bar -> /outside, -// FollowSymlinkInScope("/foo/bar", "/foo") == "/foo/outside" instead of "/oustide" -// -// IMPORTANT: it is the caller's responsibility to call evalSymlinksInScope *after* relevant symlinks -// are created and not to create subsequently, additional symlinks that could potentially make a -// previously-safe path, unsafe. Example: if /foo/bar does not exist, evalSymlinksInScope("/foo/bar", "/foo") -// would return "/foo/bar". If one makes /foo/bar a symlink to /baz subsequently, then "/foo/bar" should -// no longer be considered safely contained in "/foo". -func evalSymlinksInScope(path, root string) (string, error) { - root = filepath.Clean(root) - if path == root { - return path, nil - } - if !strings.HasPrefix(path, root) { - return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root) - } - const maxIter = 255 - originalPath := path - // given root of "/a" and path of "/a/b/../../c" we want path to be "/b/../../c" - path = path[len(root):] - if root == string(filepath.Separator) { - path = string(filepath.Separator) + path - } - if !strings.HasPrefix(path, string(filepath.Separator)) { - return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root) - } - path = filepath.Clean(path) - // consume path by taking each frontmost path element, - // expanding it if it's a symlink, and appending it to b - var b bytes.Buffer - // b here will always be considered to be the "current absolute path inside - // root" when we append paths to it, we also append a slash and use - // filepath.Clean after the loop to trim the trailing slash - for n := 0; path != ""; n++ { - if n > maxIter { - return "", errors.New("evalSymlinksInScope: too many links in " + originalPath) - } - - // find next path component, p - i := strings.IndexRune(path, filepath.Separator) - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } - - if p == "" { - continue - } - - // this takes a b.String() like "b/../" and a p like "c" and turns it - // into "/b/../c" which then gets filepath.Cleaned into "/c" and then - // root gets prepended and we Clean again (to remove any trailing slash - // if the first Clean gave us just "/") - cleanP := filepath.Clean(string(filepath.Separator) + b.String() + p) - if cleanP == string(filepath.Separator) { - // never Lstat "/" itself - b.Reset() - continue - } - fullP := filepath.Clean(root + cleanP) - - fi, err := os.Lstat(fullP) - if os.IsNotExist(err) { - // if p does not exist, accept it - b.WriteString(p) - b.WriteRune(filepath.Separator) - continue - } - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p + string(filepath.Separator)) - continue - } - - // it's a symlink, put it at the front of path - dest, err := os.Readlink(fullP) - if err != nil { - return "", err - } - if filepath.IsAbs(dest) { - b.Reset() - } - path = dest + string(filepath.Separator) + path - } - - // see note above on "fullP := ..." for why this is double-cleaned and - // what's happening here - return filepath.Clean(root + filepath.Clean(string(filepath.Separator)+b.String())), nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go deleted file mode 100644 index d47cf59b8dff7bb6287e09a2a47b1e7281d1b90b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go +++ /dev/null @@ -1,48 +0,0 @@ -// +build linux,cgo - -package term - -import ( - "syscall" - "unsafe" -) - -// #include <termios.h> -import "C" - -type Termios syscall.Termios - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - var oldState State - if err := tcget(fd, &oldState.termios); err != 0 { - return nil, err - } - - newState := oldState.termios - - C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState))) - newState.Oflag = newState.Oflag | C.OPOST - if err := tcset(fd, &newState); err != 0 { - return nil, err - } - return &oldState, nil -} - -func tcget(fd uintptr, p *Termios) syscall.Errno { - ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(p))) - if ret != 0 { - return err.(syscall.Errno) - } - return 0 -} - -func tcset(fd uintptr, p *Termios) syscall.Errno { - ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(p))) - if ret != 0 { - return err.(syscall.Errno) - } - return 0 -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_other.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_other.go deleted file mode 100644 index 266039bac3e9dc0a6dbb9d283f7d57e02efa7a78..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_other.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !windows -// +build !linux !cgo - -package term - -import ( - "syscall" - "unsafe" -) - -func tcget(fd uintptr, p *Termios) syscall.Errno { - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(p))) - return err -} - -func tcset(fd uintptr, p *Termios) syscall.Errno { - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(p))) - return err -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go deleted file mode 100644 index b945a3dcea9fb6550047c66dff0c851a8727c14c..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term.go +++ /dev/null @@ -1,118 +0,0 @@ -// +build !windows - -package term - -import ( - "errors" - "io" - "os" - "os/signal" - "syscall" - "unsafe" -) - -var ( - ErrInvalidState = errors.New("Invalid terminal state") -) - -type State struct { - termios Termios -} - -type Winsize struct { - Height uint16 - Width uint16 - x uint16 - y uint16 -} - -func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - return os.Stdin, os.Stdout, os.Stderr -} - -func GetFdInfo(in interface{}) (uintptr, bool) { - var inFd uintptr - var isTerminalIn bool - if file, ok := in.(*os.File); ok { - inFd = file.Fd() - isTerminalIn = IsTerminal(inFd) - } - return inFd, isTerminalIn -} - -func GetWinsize(fd uintptr) (*Winsize, error) { - ws := &Winsize{} - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws))) - // Skipp errno = 0 - if err == 0 { - return ws, nil - } - return ws, err -} - -func SetWinsize(fd uintptr, ws *Winsize) error { - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) - // Skipp errno = 0 - if err == 0 { - return nil - } - return err -} - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal(fd uintptr) bool { - var termios Termios - return tcget(fd, &termios) == 0 -} - -// Restore restores the terminal connected to the given file descriptor to a -// previous state. -func RestoreTerminal(fd uintptr, state *State) error { - if state == nil { - return ErrInvalidState - } - if err := tcset(fd, &state.termios); err != 0 { - return err - } - return nil -} - -func SaveState(fd uintptr) (*State, error) { - var oldState State - if err := tcget(fd, &oldState.termios); err != 0 { - return nil, err - } - - return &oldState, nil -} - -func DisableEcho(fd uintptr, state *State) error { - newState := state.termios - newState.Lflag &^= syscall.ECHO - - if err := tcset(fd, &newState); err != 0 { - return err - } - handleInterrupt(fd, state) - return nil -} - -func SetRawTerminal(fd uintptr) (*State, error) { - oldState, err := MakeRaw(fd) - if err != nil { - return nil, err - } - handleInterrupt(fd, oldState) - return oldState, err -} - -func handleInterrupt(fd uintptr, state *State) { - sigchan := make(chan os.Signal, 1) - signal.Notify(sigchan, os.Interrupt) - - go func() { - _ = <-sigchan - RestoreTerminal(fd, state) - os.Exit(0) - }() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go deleted file mode 100644 index 2c2c86b86ced6ca9446abe62267775cf43937781..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/term_windows.go +++ /dev/null @@ -1,139 +0,0 @@ -// +build windows - -package term - -import ( - "io" - "os" - - "github.com/sirupsen/logrus" - "github.com/docker/docker/pkg/term/winconsole" -) - -// State holds the console mode for the terminal. -type State struct { - mode uint32 -} - -// Winsize is used for window size. -type Winsize struct { - Height uint16 - Width uint16 - x uint16 - y uint16 -} - -func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - switch { - case os.Getenv("ConEmuANSI") == "ON": - // The ConEmu shell emulates ANSI well by default. - return os.Stdin, os.Stdout, os.Stderr - case os.Getenv("MSYSTEM") != "": - // MSYS (mingw) does not emulate ANSI well. - return winconsole.WinConsoleStreams() - default: - return winconsole.WinConsoleStreams() - } -} - -// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal. -func GetFdInfo(in interface{}) (uintptr, bool) { - return winconsole.GetHandleInfo(in) -} - -// GetWinsize retrieves the window size of the terminal connected to the passed file descriptor. -func GetWinsize(fd uintptr) (*Winsize, error) { - info, err := winconsole.GetConsoleScreenBufferInfo(fd) - if err != nil { - return nil, err - } - - // TODO(azlinux): Set the pixel width / height of the console (currently unused by any caller) - return &Winsize{ - Width: uint16(info.Window.Right - info.Window.Left + 1), - Height: uint16(info.Window.Bottom - info.Window.Top + 1), - x: 0, - y: 0}, nil -} - -// SetWinsize sets the size of the given terminal connected to the passed file descriptor. -func SetWinsize(fd uintptr, ws *Winsize) error { - // TODO(azlinux): Implement SetWinsize - logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked") - return nil -} - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal(fd uintptr) bool { - return winconsole.IsConsole(fd) -} - -// RestoreTerminal restores the terminal connected to the given file descriptor to a -// previous state. -func RestoreTerminal(fd uintptr, state *State) error { - return winconsole.SetConsoleMode(fd, state.mode) -} - -// SaveState saves the state of the terminal connected to the given file descriptor. -func SaveState(fd uintptr) (*State, error) { - mode, e := winconsole.GetConsoleMode(fd) - if e != nil { - return nil, e - } - return &State{mode}, nil -} - -// DisableEcho disables echo for the terminal connected to the given file descriptor. -// -- See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx -func DisableEcho(fd uintptr, state *State) error { - mode := state.mode - mode &^= winconsole.ENABLE_ECHO_INPUT - mode |= winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT - // TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state. - return winconsole.SetConsoleMode(fd, mode) -} - -// SetRawTerminal puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func SetRawTerminal(fd uintptr) (*State, error) { - state, err := MakeRaw(fd) - if err != nil { - return nil, err - } - // TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state. - return state, err -} - -// MakeRaw puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - state, err := SaveState(fd) - if err != nil { - return nil, err - } - - // See - // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx - // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx - mode := state.mode - - // Disable these modes - mode &^= winconsole.ENABLE_ECHO_INPUT - mode &^= winconsole.ENABLE_LINE_INPUT - mode &^= winconsole.ENABLE_MOUSE_INPUT - mode &^= winconsole.ENABLE_WINDOW_INPUT - mode &^= winconsole.ENABLE_PROCESSED_INPUT - - // Enable these modes - mode |= winconsole.ENABLE_EXTENDED_FLAGS - mode |= winconsole.ENABLE_INSERT_MODE - mode |= winconsole.ENABLE_QUICK_EDIT_MODE - - err = winconsole.SetConsoleMode(fd, mode) - if err != nil { - return nil, err - } - return state, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_darwin.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_darwin.go deleted file mode 100644 index 11cd70d10b846b9a667c787bc4e5111b61889d14..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_darwin.go +++ /dev/null @@ -1,65 +0,0 @@ -package term - -import ( - "syscall" - "unsafe" -) - -const ( - getTermios = syscall.TIOCGETA - setTermios = syscall.TIOCSETA - - IGNBRK = syscall.IGNBRK - PARMRK = syscall.PARMRK - INLCR = syscall.INLCR - IGNCR = syscall.IGNCR - ECHONL = syscall.ECHONL - CSIZE = syscall.CSIZE - ICRNL = syscall.ICRNL - ISTRIP = syscall.ISTRIP - PARENB = syscall.PARENB - ECHO = syscall.ECHO - ICANON = syscall.ICANON - ISIG = syscall.ISIG - IXON = syscall.IXON - BRKINT = syscall.BRKINT - INPCK = syscall.INPCK - OPOST = syscall.OPOST - CS8 = syscall.CS8 - IEXTEN = syscall.IEXTEN -) - -type Termios struct { - Iflag uint64 - Oflag uint64 - Cflag uint64 - Lflag uint64 - Cc [20]byte - Ispeed uint64 - Ospeed uint64 -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - var oldState State - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 { - return nil, err - } - - newState := oldState.termios - newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON) - newState.Oflag &^= OPOST - newState.Lflag &^= (ECHO | ECHONL | ICANON | ISIG | IEXTEN) - newState.Cflag &^= (CSIZE | PARENB) - newState.Cflag |= CS8 - newState.Cc[syscall.VMIN] = 1 - newState.Cc[syscall.VTIME] = 0 - - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 { - return nil, err - } - - return &oldState, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_freebsd.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_freebsd.go deleted file mode 100644 index ed3659572cc1ad0a2aa8379373d9f3fbd63f1e53..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_freebsd.go +++ /dev/null @@ -1,65 +0,0 @@ -package term - -import ( - "syscall" - "unsafe" -) - -const ( - getTermios = syscall.TIOCGETA - setTermios = syscall.TIOCSETA - - IGNBRK = syscall.IGNBRK - PARMRK = syscall.PARMRK - INLCR = syscall.INLCR - IGNCR = syscall.IGNCR - ECHONL = syscall.ECHONL - CSIZE = syscall.CSIZE - ICRNL = syscall.ICRNL - ISTRIP = syscall.ISTRIP - PARENB = syscall.PARENB - ECHO = syscall.ECHO - ICANON = syscall.ICANON - ISIG = syscall.ISIG - IXON = syscall.IXON - BRKINT = syscall.BRKINT - INPCK = syscall.INPCK - OPOST = syscall.OPOST - CS8 = syscall.CS8 - IEXTEN = syscall.IEXTEN -) - -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]byte - Ispeed uint32 - Ospeed uint32 -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - var oldState State - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 { - return nil, err - } - - newState := oldState.termios - newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON) - newState.Oflag &^= OPOST - newState.Lflag &^= (ECHO | ECHONL | ICANON | ISIG | IEXTEN) - newState.Cflag &^= (CSIZE | PARENB) - newState.Cflag |= CS8 - newState.Cc[syscall.VMIN] = 1 - newState.Cc[syscall.VTIME] = 0 - - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 { - return nil, err - } - - return &oldState, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_linux.go deleted file mode 100644 index 024187ff0664e51e5290b21435836ad0dfb7ff68..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/termios_linux.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build !cgo - -package term - -import ( - "syscall" - "unsafe" -) - -const ( - getTermios = syscall.TCGETS - setTermios = syscall.TCSETS -) - -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]byte - Ispeed uint32 - Ospeed uint32 -} - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - var oldState State - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 { - return nil, err - } - - newState := oldState.termios - - newState.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON) - newState.Oflag &^= syscall.OPOST - newState.Lflag &^= (syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN) - newState.Cflag &^= (syscall.CSIZE | syscall.PARENB) - newState.Cflag |= syscall.CS8 - - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 { - return nil, err - } - return &oldState, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/console_windows.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/console_windows.go deleted file mode 100644 index 12338f069b767590eb0675aa91ca6077a9668b5e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/console_windows.go +++ /dev/null @@ -1,1053 +0,0 @@ -// +build windows - -package winconsole - -import ( - "bytes" - "fmt" - "io" - "os" - "strconv" - "strings" - "sync" - "syscall" - "unsafe" - - "github.com/sirupsen/logrus" -) - -const ( - // Consts for Get/SetConsoleMode function - // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx - ENABLE_PROCESSED_INPUT = 0x0001 - ENABLE_LINE_INPUT = 0x0002 - ENABLE_ECHO_INPUT = 0x0004 - ENABLE_WINDOW_INPUT = 0x0008 - ENABLE_MOUSE_INPUT = 0x0010 - ENABLE_INSERT_MODE = 0x0020 - ENABLE_QUICK_EDIT_MODE = 0x0040 - ENABLE_EXTENDED_FLAGS = 0x0080 - - // If parameter is a screen buffer handle, additional values - ENABLE_PROCESSED_OUTPUT = 0x0001 - ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 - - //http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes - FOREGROUND_BLUE = 1 - FOREGROUND_GREEN = 2 - FOREGROUND_RED = 4 - FOREGROUND_INTENSITY = 8 - FOREGROUND_MASK_SET = 0x000F - FOREGROUND_MASK_UNSET = 0xFFF0 - - BACKGROUND_BLUE = 16 - BACKGROUND_GREEN = 32 - BACKGROUND_RED = 64 - BACKGROUND_INTENSITY = 128 - BACKGROUND_MASK_SET = 0x00F0 - BACKGROUND_MASK_UNSET = 0xFF0F - - COMMON_LVB_REVERSE_VIDEO = 0x4000 - COMMON_LVB_UNDERSCORE = 0x8000 - - // http://man7.org/linux/man-pages/man4/console_codes.4.html - // ECMA-48 Set Graphics Rendition - ANSI_ATTR_RESET = 0 - ANSI_ATTR_BOLD = 1 - ANSI_ATTR_DIM = 2 - ANSI_ATTR_UNDERLINE = 4 - ANSI_ATTR_BLINK = 5 - ANSI_ATTR_REVERSE = 7 - ANSI_ATTR_INVISIBLE = 8 - - ANSI_ATTR_UNDERLINE_OFF = 24 - ANSI_ATTR_BLINK_OFF = 25 - ANSI_ATTR_REVERSE_OFF = 27 - ANSI_ATTR_INVISIBLE_OFF = 8 - - ANSI_FOREGROUND_BLACK = 30 - ANSI_FOREGROUND_RED = 31 - ANSI_FOREGROUND_GREEN = 32 - ANSI_FOREGROUND_YELLOW = 33 - ANSI_FOREGROUND_BLUE = 34 - ANSI_FOREGROUND_MAGENTA = 35 - ANSI_FOREGROUND_CYAN = 36 - ANSI_FOREGROUND_WHITE = 37 - ANSI_FOREGROUND_DEFAULT = 39 - - ANSI_BACKGROUND_BLACK = 40 - ANSI_BACKGROUND_RED = 41 - ANSI_BACKGROUND_GREEN = 42 - ANSI_BACKGROUND_YELLOW = 43 - ANSI_BACKGROUND_BLUE = 44 - ANSI_BACKGROUND_MAGENTA = 45 - ANSI_BACKGROUND_CYAN = 46 - ANSI_BACKGROUND_WHITE = 47 - ANSI_BACKGROUND_DEFAULT = 49 - - ANSI_MAX_CMD_LENGTH = 256 - - MAX_INPUT_EVENTS = 128 - MAX_INPUT_BUFFER = 1024 - DEFAULT_WIDTH = 80 - DEFAULT_HEIGHT = 24 -) - -// http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx -const ( - VK_PRIOR = 0x21 // PAGE UP key - VK_NEXT = 0x22 // PAGE DOWN key - VK_END = 0x23 // END key - VK_HOME = 0x24 // HOME key - VK_LEFT = 0x25 // LEFT ARROW key - VK_UP = 0x26 // UP ARROW key - VK_RIGHT = 0x27 // RIGHT ARROW key - VK_DOWN = 0x28 // DOWN ARROW key - VK_SELECT = 0x29 // SELECT key - VK_PRINT = 0x2A // PRINT key - VK_EXECUTE = 0x2B // EXECUTE key - VK_SNAPSHOT = 0x2C // PRINT SCREEN key - VK_INSERT = 0x2D // INS key - VK_DELETE = 0x2E // DEL key - VK_HELP = 0x2F // HELP key - VK_F1 = 0x70 // F1 key - VK_F2 = 0x71 // F2 key - VK_F3 = 0x72 // F3 key - VK_F4 = 0x73 // F4 key - VK_F5 = 0x74 // F5 key - VK_F6 = 0x75 // F6 key - VK_F7 = 0x76 // F7 key - VK_F8 = 0x77 // F8 key - VK_F9 = 0x78 // F9 key - VK_F10 = 0x79 // F10 key - VK_F11 = 0x7A // F11 key - VK_F12 = 0x7B // F12 key -) - -var kernel32DLL = syscall.NewLazyDLL("kernel32.dll") - -var ( - setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode") - getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") - setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition") - setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") - fillConsoleOutputCharacterProc = kernel32DLL.NewProc("FillConsoleOutputCharacterW") - writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW") - readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW") - getNumberOfConsoleInputEventsProc = kernel32DLL.NewProc("GetNumberOfConsoleInputEvents") - getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo") - setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo") - setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo") - setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize") -) - -// types for calling various windows API -// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx -type ( - SHORT int16 - BOOL int32 - WORD uint16 - WCHAR uint16 - DWORD uint32 - - SMALL_RECT struct { - Left SHORT - Top SHORT - Right SHORT - Bottom SHORT - } - - COORD struct { - X SHORT - Y SHORT - } - - CONSOLE_SCREEN_BUFFER_INFO struct { - Size COORD - CursorPosition COORD - Attributes WORD - Window SMALL_RECT - MaximumWindowSize COORD - } - - CONSOLE_CURSOR_INFO struct { - Size DWORD - Visible BOOL - } - - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166(v=vs.85).aspx - KEY_EVENT_RECORD struct { - KeyDown BOOL - RepeatCount WORD - VirtualKeyCode WORD - VirtualScanCode WORD - UnicodeChar WCHAR - ControlKeyState DWORD - } - - INPUT_RECORD struct { - EventType WORD - KeyEvent KEY_EVENT_RECORD - } - - CHAR_INFO struct { - UnicodeChar WCHAR - Attributes WORD - } -) - -// TODO(azlinux): Basic type clean-up -// -- Convert all uses of uintptr to syscall.Handle to be consistent with Windows syscall -// -- Convert, as appropriate, types to use defined Windows types (e.g., DWORD instead of uint32) - -// Implements the TerminalEmulator interface -type WindowsTerminal struct { - outMutex sync.Mutex - inMutex sync.Mutex - inputBuffer []byte - inputSize int - inputEvents []INPUT_RECORD - screenBufferInfo *CONSOLE_SCREEN_BUFFER_INFO - inputEscapeSequence []byte -} - -func getStdHandle(stdhandle int) uintptr { - handle, err := syscall.GetStdHandle(stdhandle) - if err != nil { - panic(fmt.Errorf("could not get standard io handle %d", stdhandle)) - } - return uintptr(handle) -} - -func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { - handler := &WindowsTerminal{ - inputBuffer: make([]byte, MAX_INPUT_BUFFER), - inputEscapeSequence: []byte(KEY_ESC_CSI), - inputEvents: make([]INPUT_RECORD, MAX_INPUT_EVENTS), - } - - if IsConsole(os.Stdin.Fd()) { - stdIn = &terminalReader{ - wrappedReader: os.Stdin, - emulator: handler, - command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), - fd: getStdHandle(syscall.STD_INPUT_HANDLE), - } - } else { - stdIn = os.Stdin - } - - if IsConsole(os.Stdout.Fd()) { - stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE) - - // Save current screen buffer info - screenBufferInfo, err := GetConsoleScreenBufferInfo(stdoutHandle) - if err != nil { - // If GetConsoleScreenBufferInfo returns a nil error, it usually means that stdout is not a TTY. - // However, this is in the branch where stdout is a TTY, hence the panic. - panic("could not get console screen buffer info") - } - handler.screenBufferInfo = screenBufferInfo - - buffer = make([]CHAR_INFO, screenBufferInfo.MaximumWindowSize.X*screenBufferInfo.MaximumWindowSize.Y) - - stdOut = &terminalWriter{ - wrappedWriter: os.Stdout, - emulator: handler, - command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), - fd: stdoutHandle, - } - } else { - stdOut = os.Stdout - } - - if IsConsole(os.Stderr.Fd()) { - stdErr = &terminalWriter{ - wrappedWriter: os.Stderr, - emulator: handler, - command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), - fd: getStdHandle(syscall.STD_ERROR_HANDLE), - } - } else { - stdErr = os.Stderr - } - - return stdIn, stdOut, stdErr -} - -// GetHandleInfo returns file descriptor and bool indicating whether the file is a console. -func GetHandleInfo(in interface{}) (uintptr, bool) { - var inFd uintptr - var isTerminalIn bool - - switch t := in.(type) { - case *terminalReader: - in = t.wrappedReader - case *terminalWriter: - in = t.wrappedWriter - } - - if file, ok := in.(*os.File); ok { - inFd = file.Fd() - isTerminalIn = IsConsole(inFd) - } - return inFd, isTerminalIn -} - -func getError(r1, r2 uintptr, lastErr error) error { - // If the function fails, the return value is zero. - if r1 == 0 { - if lastErr != nil { - return lastErr - } - return syscall.EINVAL - } - return nil -} - -// GetConsoleMode gets the console mode for given file descriptor -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx -func GetConsoleMode(handle uintptr) (uint32, error) { - var mode uint32 - err := syscall.GetConsoleMode(syscall.Handle(handle), &mode) - return mode, err -} - -// SetConsoleMode sets the console mode for given file descriptor -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx -func SetConsoleMode(handle uintptr, mode uint32) error { - return getError(setConsoleModeProc.Call(handle, uintptr(mode), 0)) -} - -// SetCursorVisible sets the cursor visbility -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx -func SetCursorVisible(handle uintptr, isVisible BOOL) (bool, error) { - var cursorInfo *CONSOLE_CURSOR_INFO = &CONSOLE_CURSOR_INFO{} - if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil { - return false, err - } - cursorInfo.Visible = isVisible - if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil { - return false, err - } - return true, nil -} - -// SetWindowSize sets the size of the console window. -func SetWindowSize(handle uintptr, width, height, max SHORT) (bool, error) { - window := SMALL_RECT{Left: 0, Top: 0, Right: width - 1, Bottom: height - 1} - coord := COORD{X: width - 1, Y: max} - if err := getError(setConsoleWindowInfoProc.Call(handle, uintptr(1), uintptr(unsafe.Pointer(&window)))); err != nil { - return false, err - } - if err := getError(setConsoleScreenBufferSizeProc.Call(handle, marshal(coord))); err != nil { - return false, err - } - return true, nil -} - -// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx -func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { - var info CONSOLE_SCREEN_BUFFER_INFO - if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil { - return nil, err - } - return &info, nil -} - -// setConsoleTextAttribute sets the attributes of characters written to the -// console screen buffer by the WriteFile or WriteConsole function, -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx -func setConsoleTextAttribute(handle uintptr, attribute WORD) error { - return getError(setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)) -} - -func writeConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) (bool, error) { - if err := getError(writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), marshal(bufferSize), marshal(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))); err != nil { - return false, err - } - return true, nil -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682663(v=vs.85).aspx -func fillConsoleOutputCharacter(handle uintptr, fillChar byte, length uint32, writeCord COORD) (bool, error) { - out := int64(0) - if err := getError(fillConsoleOutputCharacterProc.Call(handle, uintptr(fillChar), uintptr(length), marshal(writeCord), uintptr(unsafe.Pointer(&out)))); err != nil { - return false, err - } - return true, nil -} - -// Gets the number of space characters to write for "clearing" the section of terminal -func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 { - // must be valid cursor position - if fromCoord.X < 0 || fromCoord.Y < 0 || toCoord.X < 0 || toCoord.Y < 0 { - return 0 - } - if fromCoord.X >= screenSize.X || fromCoord.Y >= screenSize.Y || toCoord.X >= screenSize.X || toCoord.Y >= screenSize.Y { - return 0 - } - // can't be backwards - if fromCoord.Y > toCoord.Y { - return 0 - } - // same line - if fromCoord.Y == toCoord.Y { - return uint32(toCoord.X-fromCoord.X) + 1 - } - // spans more than one line - if fromCoord.Y < toCoord.Y { - // from start till end of line for first line + from start of line till end - retValue := uint32(screenSize.X-fromCoord.X) + uint32(toCoord.X) + 1 - // don't count first and last line - linesBetween := toCoord.Y - fromCoord.Y - 1 - if linesBetween > 0 { - retValue = retValue + uint32(linesBetween*screenSize.X) - } - return retValue - } - return 0 -} - -var buffer []CHAR_INFO - -func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) { - var writeRegion SMALL_RECT - writeRegion.Left = fromCoord.X - writeRegion.Top = fromCoord.Y - writeRegion.Right = toCoord.X - writeRegion.Bottom = toCoord.Y - - // allocate and initialize buffer - width := toCoord.X - fromCoord.X + 1 - height := toCoord.Y - fromCoord.Y + 1 - size := uint32(width) * uint32(height) - if size > 0 { - buffer := make([]CHAR_INFO, size) - for i := range buffer { - buffer[i] = CHAR_INFO{WCHAR(' '), attributes} - } - - // Write to buffer - r, err := writeConsoleOutput(handle, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &writeRegion) - if !r { - if err != nil { - return 0, err - } - return 0, syscall.EINVAL - } - } - return uint32(size), nil -} - -func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) { - nw := uint32(0) - // start and end on same line - if fromCoord.Y == toCoord.Y { - return clearDisplayRect(handle, attributes, fromCoord, toCoord) - } - // TODO(azlinux): if full screen, optimize - - // spans more than one line - if fromCoord.Y < toCoord.Y { - // from start position till end of line for first line - n, err := clearDisplayRect(handle, attributes, fromCoord, COORD{X: toCoord.X, Y: fromCoord.Y}) - if err != nil { - return nw, err - } - nw += n - // lines between - linesBetween := toCoord.Y - fromCoord.Y - 1 - if linesBetween > 0 { - n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: toCoord.X, Y: toCoord.Y - 1}) - if err != nil { - return nw, err - } - nw += n - } - // lines at end - n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord) - if err != nil { - return nw, err - } - nw += n - } - return nw, nil -} - -// setConsoleCursorPosition sets the console cursor position -// Note The X and Y are zero based -// If relative is true then the new position is relative to current one -func setConsoleCursorPosition(handle uintptr, isRelative bool, column int16, line int16) error { - screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) - if err != nil { - return err - } - var position COORD - if isRelative { - position.X = screenBufferInfo.CursorPosition.X + SHORT(column) - position.Y = screenBufferInfo.CursorPosition.Y + SHORT(line) - } else { - position.X = SHORT(column) - position.Y = SHORT(line) - } - return getError(setConsoleCursorPositionProc.Call(handle, marshal(position), 0)) -} - -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683207(v=vs.85).aspx -func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) { - var n DWORD - if err := getError(getNumberOfConsoleInputEventsProc.Call(handle, uintptr(unsafe.Pointer(&n)))); err != nil { - return 0, err - } - return uint16(n), nil -} - -//http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx -func readConsoleInputKey(handle uintptr, inputBuffer []INPUT_RECORD) (int, error) { - var nr DWORD - if err := getError(readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&inputBuffer[0])), uintptr(len(inputBuffer)), uintptr(unsafe.Pointer(&nr)))); err != nil { - return 0, err - } - return int(nr), nil -} - -func getWindowsTextAttributeForAnsiValue(originalFlag WORD, defaultValue WORD, ansiValue int16) (WORD, error) { - flag := WORD(originalFlag) - if flag == 0 { - flag = defaultValue - } - switch ansiValue { - case ANSI_ATTR_RESET: - flag &^= COMMON_LVB_UNDERSCORE - flag &^= BACKGROUND_INTENSITY - flag = flag | FOREGROUND_INTENSITY - case ANSI_ATTR_INVISIBLE: - // TODO: how do you reset reverse? - case ANSI_ATTR_UNDERLINE: - flag = flag | COMMON_LVB_UNDERSCORE - case ANSI_ATTR_BLINK: - // seems like background intenisty is blink - flag = flag | BACKGROUND_INTENSITY - case ANSI_ATTR_UNDERLINE_OFF: - flag &^= COMMON_LVB_UNDERSCORE - case ANSI_ATTR_BLINK_OFF: - // seems like background intenisty is blink - flag &^= BACKGROUND_INTENSITY - case ANSI_ATTR_BOLD: - flag = flag | FOREGROUND_INTENSITY - case ANSI_ATTR_DIM: - flag &^= FOREGROUND_INTENSITY - case ANSI_ATTR_REVERSE, ANSI_ATTR_REVERSE_OFF: - // swap forground and background bits - foreground := flag & FOREGROUND_MASK_SET - background := flag & BACKGROUND_MASK_SET - flag = (flag & BACKGROUND_MASK_UNSET & FOREGROUND_MASK_UNSET) | (foreground << 4) | (background >> 4) - - // FOREGROUND - case ANSI_FOREGROUND_DEFAULT: - flag = (flag & FOREGROUND_MASK_UNSET) | (defaultValue & FOREGROUND_MASK_SET) - case ANSI_FOREGROUND_BLACK: - flag = flag ^ (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) - case ANSI_FOREGROUND_RED: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED - case ANSI_FOREGROUND_GREEN: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_GREEN - case ANSI_FOREGROUND_YELLOW: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_GREEN - case ANSI_FOREGROUND_BLUE: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_BLUE - case ANSI_FOREGROUND_MAGENTA: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_BLUE - case ANSI_FOREGROUND_CYAN: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_GREEN | FOREGROUND_BLUE - case ANSI_FOREGROUND_WHITE: - flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE - - // Background - case ANSI_BACKGROUND_DEFAULT: - // Black with no intensity - flag = (flag & BACKGROUND_MASK_UNSET) | (defaultValue & BACKGROUND_MASK_SET) - case ANSI_BACKGROUND_BLACK: - flag = (flag & BACKGROUND_MASK_UNSET) - case ANSI_BACKGROUND_RED: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED - case ANSI_BACKGROUND_GREEN: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_GREEN - case ANSI_BACKGROUND_YELLOW: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_GREEN - case ANSI_BACKGROUND_BLUE: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_BLUE - case ANSI_BACKGROUND_MAGENTA: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_BLUE - case ANSI_BACKGROUND_CYAN: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_GREEN | BACKGROUND_BLUE - case ANSI_BACKGROUND_WHITE: - flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE - } - return flag, nil -} - -// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls -func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte) (n int, err error) { - // always consider all the bytes in command, processed - n = len(command) - - parsedCommand := parseAnsiCommand(command) - logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand) - - // console settings changes need to happen in atomic way - term.outMutex.Lock() - defer term.outMutex.Unlock() - - switch parsedCommand.Command { - case "m": - // [Value;...;Valuem - // Set Graphics Mode: - // Calls the graphics functions specified by the following values. - // These specified functions remain active until the next occurrence of this escape sequence. - // Graphics mode changes the colors and attributes of text (such as bold and underline) displayed on the screen. - screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) - if err != nil { - return n, err - } - flag := screenBufferInfo.Attributes - for _, e := range parsedCommand.Parameters { - value, _ := strconv.ParseInt(e, 10, 16) // base 10, 16 bit - if value == ANSI_ATTR_RESET { - flag = term.screenBufferInfo.Attributes // reset - } else { - flag, err = getWindowsTextAttributeForAnsiValue(flag, term.screenBufferInfo.Attributes, int16(value)) - if err != nil { - return n, err - } - } - } - if err := setConsoleTextAttribute(handle, flag); err != nil { - return n, err - } - case "H", "f": - // [line;columnH - // [line;columnf - // Moves the cursor to the specified position (coordinates). - // If you do not specify a position, the cursor moves to the home position at the upper-left corner of the screen (line 0, column 0). - screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) - if err != nil { - return n, err - } - line, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) - if err != nil { - return n, err - } - if line > int16(screenBufferInfo.Window.Bottom) { - line = int16(screenBufferInfo.Window.Bottom) + 1 - } - column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1) - if err != nil { - return n, err - } - if column > int16(screenBufferInfo.Window.Right) { - column = int16(screenBufferInfo.Window.Right) + 1 - } - // The numbers are not 0 based, but 1 based - logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1) - if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil { - return n, err - } - - case "A": - // [valueA - // Moves the cursor up by the specified number of lines without changing columns. - // If the cursor is already on the top line, ignores this sequence. - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) - if err != nil { - return len(command), err - } - if err := setConsoleCursorPosition(handle, true, 0, -value); err != nil { - return n, err - } - case "B": - // [valueB - // Moves the cursor down by the specified number of lines without changing columns. - // If the cursor is already on the bottom line, ignores this sequence. - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) - if err != nil { - return n, err - } - if err := setConsoleCursorPosition(handle, true, 0, value); err != nil { - return n, err - } - case "C": - // [valueC - // Moves the cursor forward by the specified number of columns without changing lines. - // If the cursor is already in the rightmost column, ignores this sequence. - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) - if err != nil { - return n, err - } - if err := setConsoleCursorPosition(handle, true, value, 0); err != nil { - return n, err - } - case "D": - // [valueD - // Moves the cursor back by the specified number of columns without changing lines. - // If the cursor is already in the leftmost column, ignores this sequence. - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) - if err != nil { - return n, err - } - if err := setConsoleCursorPosition(handle, true, -value, 0); err != nil { - return n, err - } - case "J": - // [J Erases from the cursor to the end of the screen, including the cursor position. - // [1J Erases from the beginning of the screen to the cursor, including the cursor position. - // [2J Erases the complete display. The cursor does not move. - // Clears the screen and moves the cursor to the home position (line 0, column 0). - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0) - if err != nil { - return n, err - } - var start COORD - var cursor COORD - var end COORD - screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) - if err != nil { - return n, err - } - switch value { - case 0: - start = screenBufferInfo.CursorPosition - // end of the buffer - end.X = screenBufferInfo.Size.X - 1 - end.Y = screenBufferInfo.Size.Y - 1 - // cursor - cursor = screenBufferInfo.CursorPosition - case 1: - - // start of the screen - start.X = 0 - start.Y = 0 - // end of the screen - end = screenBufferInfo.CursorPosition - // cursor - cursor = screenBufferInfo.CursorPosition - case 2: - // start of the screen - start.X = 0 - start.Y = 0 - // end of the buffer - end.X = screenBufferInfo.Size.X - 1 - end.Y = screenBufferInfo.Size.Y - 1 - // cursor - cursor.X = 0 - cursor.Y = 0 - } - if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil { - return n, err - } - // remember the the cursor position is 1 based - if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil { - return n, err - } - - case "K": - // [K - // Clears all characters from the cursor position to the end of the line (including the character at the cursor position). - // [K Erases from the cursor to the end of the line, including the cursor position. - // [1K Erases from the beginning of the line to the cursor, including the cursor position. - // [2K Erases the complete line. - value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0) - var start COORD - var cursor COORD - var end COORD - screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle)) - if err != nil { - return n, err - } - switch value { - case 0: - // start is where cursor is - start = screenBufferInfo.CursorPosition - // end of line - end.X = screenBufferInfo.Size.X - 1 - end.Y = screenBufferInfo.CursorPosition.Y - // cursor remains the same - cursor = screenBufferInfo.CursorPosition - - case 1: - // beginning of line - start.X = 0 - start.Y = screenBufferInfo.CursorPosition.Y - // until cursor - end = screenBufferInfo.CursorPosition - // cursor remains the same - cursor = screenBufferInfo.CursorPosition - case 2: - // start of the line - start.X = 0 - start.Y = screenBufferInfo.CursorPosition.Y - 1 - // end of the line - end.X = screenBufferInfo.Size.X - 1 - end.Y = screenBufferInfo.CursorPosition.Y - 1 - // cursor - cursor.X = 0 - cursor.Y = screenBufferInfo.CursorPosition.Y - 1 - } - if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil { - return n, err - } - // remember the the cursor position is 1 based - if err := setConsoleCursorPosition(uintptr(handle), false, int16(cursor.X), int16(cursor.Y)); err != nil { - return n, err - } - - case "l": - for _, value := range parsedCommand.Parameters { - switch value { - case "?25", "25": - SetCursorVisible(uintptr(handle), BOOL(0)) - case "?1049", "1049": - // TODO (azlinux): Restore terminal - case "?1", "1": - // If the DECCKM function is reset, then the arrow keys send ANSI cursor sequences to the host. - term.inputEscapeSequence = []byte(KEY_ESC_CSI) - } - } - case "h": - for _, value := range parsedCommand.Parameters { - switch value { - case "?25", "25": - SetCursorVisible(uintptr(handle), BOOL(1)) - case "?1049", "1049": - // TODO (azlinux): Save terminal - case "?1", "1": - // If the DECCKM function is set, then the arrow keys send application sequences to the host. - // DECCKM (default off): When set, the cursor keys send an ESC O prefix, rather than ESC [. - term.inputEscapeSequence = []byte(KEY_ESC_O) - } - } - - case "]": - /* - TODO (azlinux): - Linux Console Private CSI Sequences - - The following sequences are neither ECMA-48 nor native VT102. They are - native to the Linux console driver. Colors are in SGR parameters: 0 = - black, 1 = red, 2 = green, 3 = brown, 4 = blue, 5 = magenta, 6 = cyan, - 7 = white. - - ESC [ 1 ; n ] Set color n as the underline color - ESC [ 2 ; n ] Set color n as the dim color - ESC [ 8 ] Make the current color pair the default attributes. - ESC [ 9 ; n ] Set screen blank timeout to n minutes. - ESC [ 10 ; n ] Set bell frequency in Hz. - ESC [ 11 ; n ] Set bell duration in msec. - ESC [ 12 ; n ] Bring specified console to the front. - ESC [ 13 ] Unblank the screen. - ESC [ 14 ; n ] Set the VESA powerdown interval in minutes. - - */ - } - return n, nil -} - -// WriteChars writes the bytes to given writer. -func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - return w.Write(p) -} - -const ( - CAPSLOCK_ON = 0x0080 //The CAPS LOCK light is on. - ENHANCED_KEY = 0x0100 //The key is enhanced. - LEFT_ALT_PRESSED = 0x0002 //The left ALT key is pressed. - LEFT_CTRL_PRESSED = 0x0008 //The left CTRL key is pressed. - NUMLOCK_ON = 0x0020 //The NUM LOCK light is on. - RIGHT_ALT_PRESSED = 0x0001 //The right ALT key is pressed. - RIGHT_CTRL_PRESSED = 0x0004 //The right CTRL key is pressed. - SCROLLLOCK_ON = 0x0040 //The SCROLL LOCK light is on. - SHIFT_PRESSED = 0x0010 // The SHIFT key is pressed. -) - -const ( - KEY_CONTROL_PARAM_2 = ";2" - KEY_CONTROL_PARAM_3 = ";3" - KEY_CONTROL_PARAM_4 = ";4" - KEY_CONTROL_PARAM_5 = ";5" - KEY_CONTROL_PARAM_6 = ";6" - KEY_CONTROL_PARAM_7 = ";7" - KEY_CONTROL_PARAM_8 = ";8" - KEY_ESC_CSI = "\x1B[" - KEY_ESC_N = "\x1BN" - KEY_ESC_O = "\x1BO" -) - -var keyMapPrefix = map[WORD]string{ - VK_UP: "\x1B[%sA", - VK_DOWN: "\x1B[%sB", - VK_RIGHT: "\x1B[%sC", - VK_LEFT: "\x1B[%sD", - VK_HOME: "\x1B[1%s~", // showkey shows ^[[1 - VK_END: "\x1B[4%s~", // showkey shows ^[[4 - VK_INSERT: "\x1B[2%s~", - VK_DELETE: "\x1B[3%s~", - VK_PRIOR: "\x1B[5%s~", - VK_NEXT: "\x1B[6%s~", - VK_F1: "", - VK_F2: "", - VK_F3: "\x1B[13%s~", - VK_F4: "\x1B[14%s~", - VK_F5: "\x1B[15%s~", - VK_F6: "\x1B[17%s~", - VK_F7: "\x1B[18%s~", - VK_F8: "\x1B[19%s~", - VK_F9: "\x1B[20%s~", - VK_F10: "\x1B[21%s~", - VK_F11: "\x1B[23%s~", - VK_F12: "\x1B[24%s~", -} - -var arrowKeyMapPrefix = map[WORD]string{ - VK_UP: "%s%sA", - VK_DOWN: "%s%sB", - VK_RIGHT: "%s%sC", - VK_LEFT: "%s%sD", -} - -func getControlStateParameter(shift, alt, control, meta bool) string { - if shift && alt && control { - return KEY_CONTROL_PARAM_8 - } - if alt && control { - return KEY_CONTROL_PARAM_7 - } - if shift && control { - return KEY_CONTROL_PARAM_6 - } - if control { - return KEY_CONTROL_PARAM_5 - } - if shift && alt { - return KEY_CONTROL_PARAM_4 - } - if alt { - return KEY_CONTROL_PARAM_3 - } - if shift { - return KEY_CONTROL_PARAM_2 - } - return "" -} - -func getControlKeys(controlState DWORD) (shift, alt, control bool) { - shift = 0 != (controlState & SHIFT_PRESSED) - alt = 0 != (controlState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) - control = 0 != (controlState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) - return shift, alt, control -} - -func charSequenceForKeys(key WORD, controlState DWORD, escapeSequence []byte) string { - i, ok := arrowKeyMapPrefix[key] - if ok { - shift, alt, control := getControlKeys(controlState) - modifier := getControlStateParameter(shift, alt, control, false) - return fmt.Sprintf(i, escapeSequence, modifier) - } - - i, ok = keyMapPrefix[key] - if ok { - shift, alt, control := getControlKeys(controlState) - modifier := getControlStateParameter(shift, alt, control, false) - return fmt.Sprintf(i, modifier) - } - - return "" -} - -// mapKeystokeToTerminalString maps the given input event record to string -func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []byte) string { - _, alt, control := getControlKeys(keyEvent.ControlKeyState) - if keyEvent.UnicodeChar == 0 { - return charSequenceForKeys(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence) - } - if control { - // TODO(azlinux): Implement following control sequences - // <Ctrl>-D Signals the end of input from the keyboard; also exits current shell. - // <Ctrl>-H Deletes the first character to the left of the cursor. Also called the ERASE key. - // <Ctrl>-Q Restarts printing after it has been stopped with <Ctrl>-s. - // <Ctrl>-S Suspends printing on the screen (does not stop the program). - // <Ctrl>-U Deletes all characters on the current line. Also called the KILL key. - // <Ctrl>-E Quits current command and creates a core - - } - // <Alt>+Key generates ESC N Key - if !control && alt { - return KEY_ESC_N + strings.ToLower(string(keyEvent.UnicodeChar)) - } - return string(keyEvent.UnicodeChar) -} - -// getAvailableInputEvents polls the console for availble events -// The function does not return until at least one input record has been read. -func getAvailableInputEvents(handle uintptr, inputEvents []INPUT_RECORD) (n int, err error) { - // TODO(azlinux): Why is there a for loop? Seems to me, that `n` cannot be negative. - tibor - for { - // Read number of console events available - n, err = readConsoleInputKey(handle, inputEvents) - if err != nil || n >= 0 { - return n, err - } - } -} - -// getTranslatedKeyCodes converts the input events into the string of characters -// The ansi escape sequence are used to map key strokes to the strings -func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) string { - var buf bytes.Buffer - for i := 0; i < len(inputEvents); i++ { - input := inputEvents[i] - if input.EventType == KEY_EVENT && input.KeyEvent.KeyDown != 0 { - keyString := mapKeystokeToTerminalString(&input.KeyEvent, escapeSequence) - buf.WriteString(keyString) - } - } - return buf.String() -} - -// ReadChars reads the characters from the given reader -func (term *WindowsTerminal) ReadChars(fd uintptr, r io.Reader, p []byte) (n int, err error) { - for term.inputSize == 0 { - nr, err := getAvailableInputEvents(fd, term.inputEvents) - if nr == 0 && nil != err { - return n, err - } - if nr > 0 { - keyCodes := getTranslatedKeyCodes(term.inputEvents[:nr], term.inputEscapeSequence) - term.inputSize = copy(term.inputBuffer, keyCodes) - } - } - n = copy(p, term.inputBuffer[:term.inputSize]) - term.inputSize -= n - return n, nil -} - -// HandleInputSequence interprets the input sequence command -func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) { - return 0, nil -} - -func marshal(c COORD) uintptr { - return uintptr(*((*DWORD)(unsafe.Pointer(&c)))) -} - -// IsConsole returns true if the given file descriptor is a terminal. -// -- The code assumes that GetConsoleMode will return an error for file descriptors that are not a console. -func IsConsole(fd uintptr) bool { - _, e := GetConsoleMode(fd) - return e == nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/term_emulator.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/term_emulator.go deleted file mode 100644 index 2d5edc0390e5fc8d3b9ba7391310f7d37fad42bb..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/term/winconsole/term_emulator.go +++ /dev/null @@ -1,234 +0,0 @@ -package winconsole - -import ( - "fmt" - "io" - "strconv" - "strings" -) - -// http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html -const ( - ANSI_ESCAPE_PRIMARY = 0x1B - ANSI_ESCAPE_SECONDARY = 0x5B - ANSI_COMMAND_FIRST = 0x40 - ANSI_COMMAND_LAST = 0x7E - ANSI_PARAMETER_SEP = ";" - ANSI_CMD_G0 = '(' - ANSI_CMD_G1 = ')' - ANSI_CMD_G2 = '*' - ANSI_CMD_G3 = '+' - ANSI_CMD_DECPNM = '>' - ANSI_CMD_DECPAM = '=' - ANSI_CMD_OSC = ']' - ANSI_CMD_STR_TERM = '\\' - ANSI_BEL = 0x07 - KEY_EVENT = 1 -) - -// Interface that implements terminal handling -type terminalEmulator interface { - HandleOutputCommand(fd uintptr, command []byte) (n int, err error) - HandleInputSequence(fd uintptr, command []byte) (n int, err error) - WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) - ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) -} - -type terminalWriter struct { - wrappedWriter io.Writer - emulator terminalEmulator - command []byte - inSequence bool - fd uintptr -} - -type terminalReader struct { - wrappedReader io.ReadCloser - emulator terminalEmulator - command []byte - inSequence bool - fd uintptr -} - -// http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html -func isAnsiCommandChar(b byte) bool { - switch { - case ANSI_COMMAND_FIRST <= b && b <= ANSI_COMMAND_LAST && b != ANSI_ESCAPE_SECONDARY: - return true - case b == ANSI_CMD_G1 || b == ANSI_CMD_OSC || b == ANSI_CMD_DECPAM || b == ANSI_CMD_DECPNM: - // non-CSI escape sequence terminator - return true - case b == ANSI_CMD_STR_TERM || b == ANSI_BEL: - // String escape sequence terminator - return true - } - return false -} - -func isCharacterSelectionCmdChar(b byte) bool { - return (b == ANSI_CMD_G0 || b == ANSI_CMD_G1 || b == ANSI_CMD_G2 || b == ANSI_CMD_G3) -} - -func isXtermOscSequence(command []byte, current byte) bool { - return (len(command) >= 2 && command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_CMD_OSC && current != ANSI_BEL) -} - -// Write writes len(p) bytes from p to the underlying data stream. -// http://golang.org/pkg/io/#Writer -func (tw *terminalWriter) Write(p []byte) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if tw.emulator == nil { - return tw.wrappedWriter.Write(p) - } - // Emulate terminal by extracting commands and executing them - totalWritten := 0 - start := 0 // indicates start of the next chunk - end := len(p) - for current := 0; current < end; current++ { - if tw.inSequence { - // inside escape sequence - tw.command = append(tw.command, p[current]) - if isAnsiCommandChar(p[current]) { - if !isXtermOscSequence(tw.command, p[current]) { - // found the last command character. - // Now we have a complete command. - nchar, err := tw.emulator.HandleOutputCommand(tw.fd, tw.command) - totalWritten += nchar - if err != nil { - return totalWritten, err - } - - // clear the command - // don't include current character again - tw.command = tw.command[:0] - start = current + 1 - tw.inSequence = false - } - } - } else { - if p[current] == ANSI_ESCAPE_PRIMARY { - // entering escape sequnce - tw.inSequence = true - // indicates end of "normal sequence", write whatever you have so far - if len(p[start:current]) > 0 { - nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:current]) - totalWritten += nw - if err != nil { - return totalWritten, err - } - } - // include the current character as part of the next sequence - tw.command = append(tw.command, p[current]) - } - } - } - // note that so far, start of the escape sequence triggers writing out of bytes to console. - // For the part _after_ the end of last escape sequence, it is not written out yet. So write it out - if !tw.inSequence { - // assumption is that we can't be inside sequence and therefore command should be empty - if len(p[start:]) > 0 { - nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:]) - totalWritten += nw - if err != nil { - return totalWritten, err - } - } - } - return totalWritten, nil - -} - -// Read reads up to len(p) bytes into p. -// http://golang.org/pkg/io/#Reader -func (tr *terminalReader) Read(p []byte) (n int, err error) { - //Implementations of Read are discouraged from returning a zero byte count - // with a nil error, except when len(p) == 0. - if len(p) == 0 { - return 0, nil - } - if nil == tr.emulator { - return tr.readFromWrappedReader(p) - } - return tr.emulator.ReadChars(tr.fd, tr.wrappedReader, p) -} - -// Close the underlying stream -func (tr *terminalReader) Close() (err error) { - return tr.wrappedReader.Close() -} - -func (tr *terminalReader) readFromWrappedReader(p []byte) (n int, err error) { - return tr.wrappedReader.Read(p) -} - -type ansiCommand struct { - CommandBytes []byte - Command string - Parameters []string - IsSpecial bool -} - -func parseAnsiCommand(command []byte) *ansiCommand { - if isCharacterSelectionCmdChar(command[1]) { - // Is Character Set Selection commands - return &ansiCommand{ - CommandBytes: command, - Command: string(command), - IsSpecial: true, - } - } - // last char is command character - lastCharIndex := len(command) - 1 - - retValue := &ansiCommand{ - CommandBytes: command, - Command: string(command[lastCharIndex]), - IsSpecial: false, - } - // more than a single escape - if lastCharIndex != 0 { - start := 1 - // skip if double char escape sequence - if command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_ESCAPE_SECONDARY { - start++ - } - // convert this to GetNextParam method - retValue.Parameters = strings.Split(string(command[start:lastCharIndex]), ANSI_PARAMETER_SEP) - } - return retValue -} - -func (c *ansiCommand) getParam(index int) string { - if len(c.Parameters) > index { - return c.Parameters[index] - } - return "" -} - -func (ac *ansiCommand) String() string { - return fmt.Sprintf("0x%v \"%v\" (\"%v\")", - bytesToHex(ac.CommandBytes), - ac.Command, - strings.Join(ac.Parameters, "\",\"")) -} - -func bytesToHex(b []byte) string { - hex := make([]string, len(b)) - for i, ch := range b { - hex[i] = fmt.Sprintf("%X", ch) - } - return strings.Join(hex, "") -} - -func parseInt16OrDefault(s string, defaultValue int16) (n int16, err error) { - if s == "" { - return defaultValue, nil - } - parsedValue, err := strconv.ParseInt(s, 10, 16) - if err != nil { - return defaultValue, err - } - return int16(parsedValue), nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/LICENSE deleted file mode 100644 index b55b37bc3162090c6e7c3458fbe0771089ef633b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2015 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/duration.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/duration.go deleted file mode 100644 index c219a8a968c40035a4f3a44d448f94ac4bceece9..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/duration.go +++ /dev/null @@ -1,33 +0,0 @@ -// Package units provides helper function to parse and print size and time units -// in human-readable format. -package units - -import ( - "fmt" - "time" -) - -// HumanDuration returns a human-readable approximation of a duration -// (eg. "About a minute", "4 hours ago", etc.). -func HumanDuration(d time.Duration) string { - if seconds := int(d.Seconds()); seconds < 1 { - return "Less than a second" - } else if seconds < 60 { - return fmt.Sprintf("%d seconds", seconds) - } else if minutes := int(d.Minutes()); minutes == 1 { - return "About a minute" - } else if minutes < 60 { - return fmt.Sprintf("%d minutes", minutes) - } else if hours := int(d.Hours()); hours == 1 { - return "About an hour" - } else if hours < 48 { - return fmt.Sprintf("%d hours", hours) - } else if hours < 24*7*2 { - return fmt.Sprintf("%d days", hours/24) - } else if hours < 24*30*3 { - return fmt.Sprintf("%d weeks", hours/24/7) - } else if hours < 24*365*2 { - return fmt.Sprintf("%d months", hours/24/30) - } - return fmt.Sprintf("%d years", int(d.Hours())/24/365) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/size.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/size.go deleted file mode 100644 index 3b59daff31b73be02f2fc36b7f172cd7dc187657..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/go-units/size.go +++ /dev/null @@ -1,95 +0,0 @@ -package units - -import ( - "fmt" - "regexp" - "strconv" - "strings" -) - -// See: http://en.wikipedia.org/wiki/Binary_prefix -const ( - // Decimal - - KB = 1000 - MB = 1000 * KB - GB = 1000 * MB - TB = 1000 * GB - PB = 1000 * TB - - // Binary - - KiB = 1024 - MiB = 1024 * KiB - GiB = 1024 * MiB - TiB = 1024 * GiB - PiB = 1024 * TiB -) - -type unitMap map[string]int64 - -var ( - decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB} - binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB} - sizeRegex = regexp.MustCompile(`^(\d+)([kKmMgGtTpP])?[bB]?$`) -) - -var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} -var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} - -// CustomSize returns a human-readable approximation of a size -// using custom format. -func CustomSize(format string, size float64, base float64, _map []string) string { - i := 0 - for size >= base { - size = size / base - i++ - } - return fmt.Sprintf(format, size, _map[i]) -} - -// HumanSize returns a human-readable approximation of a size -// capped at 4 valid numbers (eg. "2.746 MB", "796 KB"). -func HumanSize(size float64) string { - return CustomSize("%.4g %s", size, 1000.0, decimapAbbrs) -} - -// BytesSize returns a human-readable size in bytes, kibibytes, -// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB"). -func BytesSize(size float64) string { - return CustomSize("%.4g %s", size, 1024.0, binaryAbbrs) -} - -// FromHumanSize returns an integer from a human-readable specification of a -// size using SI standard (eg. "44kB", "17MB"). -func FromHumanSize(size string) (int64, error) { - return parseSize(size, decimalMap) -} - -// RAMInBytes parses a human-readable string representing an amount of RAM -// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and -// returns the number of bytes, or -1 if the string is unparseable. -// Units are case-insensitive, and the 'b' suffix is optional. -func RAMInBytes(size string) (int64, error) { - return parseSize(size, binaryMap) -} - -// Parses the human-readable size string into the amount it represents. -func parseSize(sizeStr string, uMap unitMap) (int64, error) { - matches := sizeRegex.FindStringSubmatch(sizeStr) - if len(matches) != 3 { - return -1, fmt.Errorf("invalid size: '%s'", sizeStr) - } - - size, err := strconv.ParseInt(matches[1], 10, 0) - if err != nil { - return -1, err - } - - unitPrefix := strings.ToLower(matches[2]) - if mul, ok := uMap[unitPrefix]; ok { - size *= mul - } - - return size, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE deleted file mode 100644 index 670d88fcaaf0bcbca03a7179bad8b83393607b7f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>), Google -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth.go deleted file mode 100644 index 98017b693eec505bc9907d1a964081806a04e182..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth.go +++ /dev/null @@ -1,253 +0,0 @@ -package dbus - -import ( - "bufio" - "bytes" - "errors" - "io" - "os" - "strconv" -) - -// AuthStatus represents the Status of an authentication mechanism. -type AuthStatus byte - -const ( - // AuthOk signals that authentication is finished; the next command - // from the server should be an OK. - AuthOk AuthStatus = iota - - // AuthContinue signals that additional data is needed; the next command - // from the server should be a DATA. - AuthContinue - - // AuthError signals an error; the server sent invalid data or some - // other unexpected thing happened and the current authentication - // process should be aborted. - AuthError -) - -type authState byte - -const ( - waitingForData authState = iota - waitingForOk - waitingForReject -) - -// Auth defines the behaviour of an authentication mechanism. -type Auth interface { - // Return the name of the mechnism, the argument to the first AUTH command - // and the next status. - FirstData() (name, resp []byte, status AuthStatus) - - // Process the given DATA command, and return the argument to the DATA - // command and the next status. If len(resp) == 0, no DATA command is sent. - HandleData(data []byte) (resp []byte, status AuthStatus) -} - -// Auth authenticates the connection, trying the given list of authentication -// mechanisms (in that order). If nil is passed, the EXTERNAL and -// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private -// connections, this method must be called before sending any messages to the -// bus. Auth must not be called on shared connections. -func (conn *Conn) Auth(methods []Auth) error { - if methods == nil { - uid := strconv.Itoa(os.Getuid()) - methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} - } - in := bufio.NewReader(conn.transport) - err := conn.transport.SendNullByte() - if err != nil { - return err - } - err = authWriteLine(conn.transport, []byte("AUTH")) - if err != nil { - return err - } - s, err := authReadLine(in) - if err != nil { - return err - } - if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) { - return errors.New("dbus: authentication protocol error") - } - s = s[1:] - for _, v := range s { - for _, m := range methods { - if name, data, status := m.FirstData(); bytes.Equal(v, name) { - var ok bool - err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data) - if err != nil { - return err - } - switch status { - case AuthOk: - err, ok = conn.tryAuth(m, waitingForOk, in) - case AuthContinue: - err, ok = conn.tryAuth(m, waitingForData, in) - default: - panic("dbus: invalid authentication status") - } - if err != nil { - return err - } - if ok { - if conn.transport.SupportsUnixFDs() { - err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD")) - if err != nil { - return err - } - line, err := authReadLine(in) - if err != nil { - return err - } - switch { - case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")): - conn.EnableUnixFDs() - conn.unixFD = true - case bytes.Equal(line[0], []byte("ERROR")): - default: - return errors.New("dbus: authentication protocol error") - } - } - err = authWriteLine(conn.transport, []byte("BEGIN")) - if err != nil { - return err - } - go conn.inWorker() - go conn.outWorker() - return nil - } - } - } - } - return errors.New("dbus: authentication failed") -} - -// tryAuth tries to authenticate with m as the mechanism, using state as the -// initial authState and in for reading input. It returns (nil, true) on -// success, (nil, false) on a REJECTED and (someErr, false) if some other -// error occured. -func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) { - for { - s, err := authReadLine(in) - if err != nil { - return err, false - } - switch { - case state == waitingForData && string(s[0]) == "DATA": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - continue - } - data, status := m.HandleData(s[1]) - switch status { - case AuthOk, AuthContinue: - if len(data) != 0 { - err = authWriteLine(conn.transport, []byte("DATA"), data) - if err != nil { - return err, false - } - } - if status == AuthOk { - state = waitingForOk - } - case AuthError: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - } - case state == waitingForData && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForData && string(s[0]) == "ERROR": - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - case state == waitingForData && string(s[0]) == "OK": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - } - conn.uuid = string(s[1]) - return nil, true - case state == waitingForData: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - case state == waitingForOk && string(s[0]) == "OK": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - } - conn.uuid = string(s[1]) - return nil, true - case state == waitingForOk && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForOk && (string(s[0]) == "DATA" || - string(s[0]) == "ERROR"): - - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - case state == waitingForOk: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - case state == waitingForReject && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForReject: - return errors.New("dbus: authentication protocol error"), false - default: - panic("dbus: invalid auth state") - } - } -} - -// authReadLine reads a line and separates it into its fields. -func authReadLine(in *bufio.Reader) ([][]byte, error) { - data, err := in.ReadBytes('\n') - if err != nil { - return nil, err - } - data = bytes.TrimSuffix(data, []byte("\r\n")) - return bytes.Split(data, []byte{' '}), nil -} - -// authWriteLine writes the given line in the authentication protocol format -// (elements of data separated by a " " and terminated by "\r\n"). -func authWriteLine(out io.Writer, data ...[]byte) error { - buf := make([]byte, 0) - for i, v := range data { - buf = append(buf, v...) - if i != len(data)-1 { - buf = append(buf, ' ') - } - } - buf = append(buf, '\r') - buf = append(buf, '\n') - n, err := out.Write(buf) - if err != nil { - return err - } - if n != len(buf) { - return io.ErrUnexpectedEOF - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_external.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_external.go deleted file mode 100644 index 7e376d3ef6adc98516df592840141abcd8e41e81..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_external.go +++ /dev/null @@ -1,26 +0,0 @@ -package dbus - -import ( - "encoding/hex" -) - -// AuthExternal returns an Auth that authenticates as the given user with the -// EXTERNAL mechanism. -func AuthExternal(user string) Auth { - return authExternal{user} -} - -// AuthExternal implements the EXTERNAL authentication mechanism. -type authExternal struct { - user string -} - -func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) { - b := make([]byte, 2*len(a.user)) - hex.Encode(b, []byte(a.user)) - return []byte("EXTERNAL"), b, AuthOk -} - -func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) { - return nil, AuthError -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_sha1.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_sha1.go deleted file mode 100644 index df15b46119895b5d08e4477b3bd76bd2f889892c..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/auth_sha1.go +++ /dev/null @@ -1,102 +0,0 @@ -package dbus - -import ( - "bufio" - "bytes" - "crypto/rand" - "crypto/sha1" - "encoding/hex" - "os" -) - -// AuthCookieSha1 returns an Auth that authenticates as the given user with the -// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home -// directory of the user. -func AuthCookieSha1(user, home string) Auth { - return authCookieSha1{user, home} -} - -type authCookieSha1 struct { - user, home string -} - -func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) { - b := make([]byte, 2*len(a.user)) - hex.Encode(b, []byte(a.user)) - return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue -} - -func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) { - challenge := make([]byte, len(data)/2) - _, err := hex.Decode(challenge, data) - if err != nil { - return nil, AuthError - } - b := bytes.Split(challenge, []byte{' '}) - if len(b) != 3 { - return nil, AuthError - } - context := b[0] - id := b[1] - svchallenge := b[2] - cookie := a.getCookie(context, id) - if cookie == nil { - return nil, AuthError - } - clchallenge := a.generateChallenge() - if clchallenge == nil { - return nil, AuthError - } - hash := sha1.New() - hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'})) - hexhash := make([]byte, 2*hash.Size()) - hex.Encode(hexhash, hash.Sum(nil)) - data = append(clchallenge, ' ') - data = append(data, hexhash...) - resp := make([]byte, 2*len(data)) - hex.Encode(resp, data) - return resp, AuthOk -} - -// getCookie searches for the cookie identified by id in context and returns -// the cookie content or nil. (Since HandleData can't return a specific error, -// but only whether an error occured, this function also doesn't bother to -// return an error.) -func (a authCookieSha1) getCookie(context, id []byte) []byte { - file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context)) - if err != nil { - return nil - } - defer file.Close() - rd := bufio.NewReader(file) - for { - line, err := rd.ReadBytes('\n') - if err != nil { - return nil - } - line = line[:len(line)-1] - b := bytes.Split(line, []byte{' '}) - if len(b) != 3 { - return nil - } - if bytes.Equal(b[0], id) { - return b[2] - } - } -} - -// generateChallenge returns a random, hex-encoded challenge, or nil on error -// (see above). -func (a authCookieSha1) generateChallenge() []byte { - b := make([]byte, 16) - n, err := rand.Read(b) - if err != nil { - return nil - } - if n != 16 { - return nil - } - enc := make([]byte, 32) - hex.Encode(enc, b) - return enc -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/call.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/call.go deleted file mode 100644 index ba6e73f607a9d7f9e53e972363979439706f8e68..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/call.go +++ /dev/null @@ -1,36 +0,0 @@ -package dbus - -import ( - "errors" -) - -// Call represents a pending or completed method call. -type Call struct { - Destination string - Path ObjectPath - Method string - Args []interface{} - - // Strobes when the call is complete. - Done chan *Call - - // After completion, the error status. If this is non-nil, it may be an - // error message from the peer (with Error as its type) or some other error. - Err error - - // Holds the response once the call is done. - Body []interface{} -} - -var errSignature = errors.New("dbus: mismatched signature") - -// Store stores the body of the reply into the provided pointers. It returns -// an error if the signatures of the body and retvalues don't match, or if -// the error status is not nil. -func (c *Call) Store(retvalues ...interface{}) error { - if c.Err != nil { - return c.Err - } - - return Store(c.Body, retvalues...) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn.go deleted file mode 100644 index a4f5394010a1f15eb5e1b37b8ff8baa68b519c1d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn.go +++ /dev/null @@ -1,625 +0,0 @@ -package dbus - -import ( - "errors" - "io" - "os" - "reflect" - "strings" - "sync" -) - -const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" - -var ( - systemBus *Conn - systemBusLck sync.Mutex - sessionBus *Conn - sessionBusLck sync.Mutex -) - -// ErrClosed is the error returned by calls on a closed connection. -var ErrClosed = errors.New("dbus: connection closed by user") - -// Conn represents a connection to a message bus (usually, the system or -// session bus). -// -// Connections are either shared or private. Shared connections -// are shared between calls to the functions that return them. As a result, -// the methods Close, Auth and Hello must not be called on them. -// -// Multiple goroutines may invoke methods on a connection simultaneously. -type Conn struct { - transport - - busObj BusObject - unixFD bool - uuid string - - names []string - namesLck sync.RWMutex - - serialLck sync.Mutex - nextSerial uint32 - serialUsed map[uint32]bool - - calls map[uint32]*Call - callsLck sync.RWMutex - - handlers map[ObjectPath]map[string]exportWithMapping - handlersLck sync.RWMutex - - out chan *Message - closed bool - outLck sync.RWMutex - - signals []chan<- *Signal - signalsLck sync.Mutex - - eavesdropped chan<- *Message - eavesdroppedLck sync.Mutex -} - -// SessionBus returns a shared connection to the session bus, connecting to it -// if not already done. -func SessionBus() (conn *Conn, err error) { - sessionBusLck.Lock() - defer sessionBusLck.Unlock() - if sessionBus != nil { - return sessionBus, nil - } - defer func() { - if conn != nil { - sessionBus = conn - } - }() - conn, err = SessionBusPrivate() - if err != nil { - return - } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return - } - if err = conn.Hello(); err != nil { - conn.Close() - conn = nil - } - return -} - -// SessionBusPrivate returns a new private connection to the session bus. -func SessionBusPrivate() (*Conn, error) { - address := os.Getenv("DBUS_SESSION_BUS_ADDRESS") - if address != "" && address != "autolaunch:" { - return Dial(address) - } - - return sessionBusPlatform() -} - -// SystemBus returns a shared connection to the system bus, connecting to it if -// not already done. -func SystemBus() (conn *Conn, err error) { - systemBusLck.Lock() - defer systemBusLck.Unlock() - if systemBus != nil { - return systemBus, nil - } - defer func() { - if conn != nil { - systemBus = conn - } - }() - conn, err = SystemBusPrivate() - if err != nil { - return - } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return - } - if err = conn.Hello(); err != nil { - conn.Close() - conn = nil - } - return -} - -// SystemBusPrivate returns a new private connection to the system bus. -func SystemBusPrivate() (*Conn, error) { - address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") - if address != "" { - return Dial(address) - } - return Dial(defaultSystemBusAddress) -} - -// Dial establishes a new private connection to the message bus specified by address. -func Dial(address string) (*Conn, error) { - tr, err := getTransport(address) - if err != nil { - return nil, err - } - return newConn(tr) -} - -// NewConn creates a new private *Conn from an already established connection. -func NewConn(conn io.ReadWriteCloser) (*Conn, error) { - return newConn(genericTransport{conn}) -} - -// newConn creates a new *Conn from a transport. -func newConn(tr transport) (*Conn, error) { - conn := new(Conn) - conn.transport = tr - conn.calls = make(map[uint32]*Call) - conn.out = make(chan *Message, 10) - conn.handlers = make(map[ObjectPath]map[string]exportWithMapping) - conn.nextSerial = 1 - conn.serialUsed = map[uint32]bool{0: true} - conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") - return conn, nil -} - -// BusObject returns the object owned by the bus daemon which handles -// administrative requests. -func (conn *Conn) BusObject() BusObject { - return conn.busObj -} - -// Close closes the connection. Any blocked operations will return with errors -// and the channels passed to Eavesdrop and Signal are closed. This method must -// not be called on shared connections. -func (conn *Conn) Close() error { - conn.outLck.Lock() - if conn.closed { - // inWorker calls Close on read error, the read error may - // be caused by another caller calling Close to shutdown the - // dbus connection, a double-close scenario we prevent here. - conn.outLck.Unlock() - return nil - } - close(conn.out) - conn.closed = true - conn.outLck.Unlock() - conn.signalsLck.Lock() - for _, ch := range conn.signals { - close(ch) - } - conn.signalsLck.Unlock() - conn.eavesdroppedLck.Lock() - if conn.eavesdropped != nil { - close(conn.eavesdropped) - } - conn.eavesdroppedLck.Unlock() - return conn.transport.Close() -} - -// Eavesdrop causes conn to send all incoming messages to the given channel -// without further processing. Method replies, errors and signals will not be -// sent to the appropiate channels and method calls will not be handled. If nil -// is passed, the normal behaviour is restored. -// -// The caller has to make sure that ch is sufficiently buffered; -// if a message arrives when a write to ch is not possible, the message is -// discarded. -func (conn *Conn) Eavesdrop(ch chan<- *Message) { - conn.eavesdroppedLck.Lock() - conn.eavesdropped = ch - conn.eavesdroppedLck.Unlock() -} - -// getSerial returns an unused serial. -func (conn *Conn) getSerial() uint32 { - conn.serialLck.Lock() - defer conn.serialLck.Unlock() - n := conn.nextSerial - for conn.serialUsed[n] { - n++ - } - conn.serialUsed[n] = true - conn.nextSerial = n + 1 - return n -} - -// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be -// called after authentication, but before sending any other messages to the -// bus. Hello must not be called for shared connections. -func (conn *Conn) Hello() error { - var s string - err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s) - if err != nil { - return err - } - conn.namesLck.Lock() - conn.names = make([]string, 1) - conn.names[0] = s - conn.namesLck.Unlock() - return nil -} - -// inWorker runs in an own goroutine, reading incoming messages from the -// transport and dispatching them appropiately. -func (conn *Conn) inWorker() { - for { - msg, err := conn.ReadMessage() - if err == nil { - conn.eavesdroppedLck.Lock() - if conn.eavesdropped != nil { - select { - case conn.eavesdropped <- msg: - default: - } - conn.eavesdroppedLck.Unlock() - continue - } - conn.eavesdroppedLck.Unlock() - dest, _ := msg.Headers[FieldDestination].value.(string) - found := false - if dest == "" { - found = true - } else { - conn.namesLck.RLock() - if len(conn.names) == 0 { - found = true - } - for _, v := range conn.names { - if dest == v { - found = true - break - } - } - conn.namesLck.RUnlock() - } - if !found { - // Eavesdropped a message, but no channel for it is registered. - // Ignore it. - continue - } - switch msg.Type { - case TypeMethodReply, TypeError: - serial := msg.Headers[FieldReplySerial].value.(uint32) - conn.callsLck.Lock() - if c, ok := conn.calls[serial]; ok { - if msg.Type == TypeError { - name, _ := msg.Headers[FieldErrorName].value.(string) - c.Err = Error{name, msg.Body} - } else { - c.Body = msg.Body - } - c.Done <- c - conn.serialLck.Lock() - delete(conn.serialUsed, serial) - conn.serialLck.Unlock() - delete(conn.calls, serial) - } - conn.callsLck.Unlock() - case TypeSignal: - iface := msg.Headers[FieldInterface].value.(string) - member := msg.Headers[FieldMember].value.(string) - // as per http://dbus.freedesktop.org/doc/dbus-specification.html , - // sender is optional for signals. - sender, _ := msg.Headers[FieldSender].value.(string) - if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { - if member == "NameLost" { - // If we lost the name on the bus, remove it from our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the lost name") - } - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - conn.names = append(conn.names[:i], - conn.names[i+1:]...) - } - } - conn.namesLck.Unlock() - } else if member == "NameAcquired" { - // If we acquired the name on the bus, add it to our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the acquired name") - } - conn.namesLck.Lock() - conn.names = append(conn.names, name) - conn.namesLck.Unlock() - } - } - signal := &Signal{ - Sender: sender, - Path: msg.Headers[FieldPath].value.(ObjectPath), - Name: iface + "." + member, - Body: msg.Body, - } - conn.signalsLck.Lock() - for _, ch := range conn.signals { - ch <- signal - } - conn.signalsLck.Unlock() - case TypeMethodCall: - go conn.handleCall(msg) - } - } else if _, ok := err.(InvalidMessageError); !ok { - // Some read error occured (usually EOF); we can't really do - // anything but to shut down all stuff and returns errors to all - // pending replies. - conn.Close() - conn.callsLck.RLock() - for _, v := range conn.calls { - v.Err = err - v.Done <- v - } - conn.callsLck.RUnlock() - return - } - // invalid messages are ignored - } -} - -// Names returns the list of all names that are currently owned by this -// connection. The slice is always at least one element long, the first element -// being the unique name of the connection. -func (conn *Conn) Names() []string { - conn.namesLck.RLock() - // copy the slice so it can't be modified - s := make([]string, len(conn.names)) - copy(s, conn.names) - conn.namesLck.RUnlock() - return s -} - -// Object returns the object identified by the given destination name and path. -func (conn *Conn) Object(dest string, path ObjectPath) BusObject { - return &Object{conn, dest, path} -} - -// outWorker runs in an own goroutine, encoding and sending messages that are -// sent to conn.out. -func (conn *Conn) outWorker() { - for msg := range conn.out { - err := conn.SendMessage(msg) - conn.callsLck.RLock() - if err != nil { - if c := conn.calls[msg.serial]; c != nil { - c.Err = err - c.Done <- c - } - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } else if msg.Type != TypeMethodCall { - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } - conn.callsLck.RUnlock() - } -} - -// Send sends the given message to the message bus. You usually don't need to -// use this; use the higher-level equivalents (Call / Go, Emit and Export) -// instead. If msg is a method call and NoReplyExpected is not set, a non-nil -// call is returned and the same value is sent to ch (which must be buffered) -// once the call is complete. Otherwise, ch is ignored and a Call structure is -// returned of which only the Err member is valid. -func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { - var call *Call - - msg.serial = conn.getSerial() - if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 5) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Conn).Send") - } - call = new(Call) - call.Destination, _ = msg.Headers[FieldDestination].value.(string) - call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) - iface, _ := msg.Headers[FieldInterface].value.(string) - member, _ := msg.Headers[FieldMember].value.(string) - call.Method = iface + "." + member - call.Args = msg.Body - call.Done = ch - conn.callsLck.Lock() - conn.calls[msg.serial] = call - conn.callsLck.Unlock() - conn.outLck.RLock() - if conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - conn.out <- msg - } - conn.outLck.RUnlock() - } else { - conn.outLck.RLock() - if conn.closed { - call = &Call{Err: ErrClosed} - } else { - conn.out <- msg - call = &Call{Err: nil} - } - conn.outLck.RUnlock() - } - return call -} - -// sendError creates an error message corresponding to the parameters and sends -// it to conn.out. -func (conn *Conn) sendError(e Error, dest string, serial uint32) { - msg := new(Message) - msg.Type = TypeError - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - if dest != "" { - msg.Headers[FieldDestination] = MakeVariant(dest) - } - msg.Headers[FieldErrorName] = MakeVariant(e.Name) - msg.Headers[FieldReplySerial] = MakeVariant(serial) - msg.Body = e.Body - if len(e.Body) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() -} - -// sendReply creates a method reply message corresponding to the parameters and -// sends it to conn.out. -func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { - msg := new(Message) - msg.Type = TypeMethodReply - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - if dest != "" { - msg.Headers[FieldDestination] = MakeVariant(dest) - } - msg.Headers[FieldReplySerial] = MakeVariant(serial) - msg.Body = values - if len(values) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() -} - -// Signal registers the given channel to be passed all received signal messages. -// The caller has to make sure that ch is sufficiently buffered; if a message -// arrives when a write to c is not possible, it is discarded. -// -// Multiple of these channels can be registered at the same time. Passing a -// channel that already is registered will remove it from the list of the -// registered channels. -// -// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a -// channel for eavesdropped messages, this channel receives all signals, and -// none of the channels passed to Signal will receive any signals. -func (conn *Conn) Signal(ch chan<- *Signal) { - conn.signalsLck.Lock() - conn.signals = append(conn.signals, ch) - conn.signalsLck.Unlock() -} - -// SupportsUnixFDs returns whether the underlying transport supports passing of -// unix file descriptors. If this is false, method calls containing unix file -// descriptors will return an error and emitted signals containing them will -// not be sent. -func (conn *Conn) SupportsUnixFDs() bool { - return conn.unixFD -} - -// Error represents a D-Bus message of type Error. -type Error struct { - Name string - Body []interface{} -} - -func NewError(name string, body []interface{}) *Error { - return &Error{name, body} -} - -func (e Error) Error() string { - if len(e.Body) >= 1 { - s, ok := e.Body[0].(string) - if ok { - return s - } - } - return e.Name -} - -// Signal represents a D-Bus message of type Signal. The name member is given in -// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. -type Signal struct { - Sender string - Path ObjectPath - Name string - Body []interface{} -} - -// transport is a D-Bus transport. -type transport interface { - // Read and Write raw data (for example, for the authentication protocol). - io.ReadWriteCloser - - // Send the initial null byte used for the EXTERNAL mechanism. - SendNullByte() error - - // Returns whether this transport supports passing Unix FDs. - SupportsUnixFDs() bool - - // Signal the transport that Unix FD passing is enabled for this connection. - EnableUnixFDs() - - // Read / send a message, handling things like Unix FDs. - ReadMessage() (*Message, error) - SendMessage(*Message) error -} - -var ( - transports = make(map[string]func(string) (transport, error)) -) - -func getTransport(address string) (transport, error) { - var err error - var t transport - - addresses := strings.Split(address, ";") - for _, v := range addresses { - i := strings.IndexRune(v, ':') - if i == -1 { - err = errors.New("dbus: invalid bus address (no transport)") - continue - } - f := transports[v[:i]] - if f == nil { - err = errors.New("dbus: invalid bus address (invalid or unsupported transport)") - continue - } - t, err = f(v[i+1:]) - if err == nil { - return t, nil - } - } - return nil, err -} - -// dereferenceAll returns a slice that, assuming that vs is a slice of pointers -// of arbitrary types, containes the values that are obtained from dereferencing -// all elements in vs. -func dereferenceAll(vs []interface{}) []interface{} { - for i := range vs { - v := reflect.ValueOf(vs[i]) - v = v.Elem() - vs[i] = v.Interface() - } - return vs -} - -// getKey gets a key from a the list of keys. Returns "" on error / not found... -func getKey(s, key string) string { - i := strings.Index(s, key) - if i == -1 { - return "" - } - if i+len(key)+1 >= len(s) || s[i+len(key)] != '=' { - return "" - } - j := strings.Index(s, ",") - if j == -1 { - j = len(s) - } - return s[i+len(key)+1 : j] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_darwin.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_darwin.go deleted file mode 100644 index b67bb1b81da68a64fe0c5221f4dafe4f429d5228..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_darwin.go +++ /dev/null @@ -1,21 +0,0 @@ -package dbus - -import ( - "errors" - "os/exec" -) - -func sessionBusPlatform() (*Conn, error) { - cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET") - b, err := cmd.CombinedOutput() - - if err != nil { - return nil, err - } - - if len(b) == 0 { - return nil, errors.New("dbus: couldn't determine address of session bus") - } - - return Dial("unix:path=" + string(b[:len(b)-1])) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_other.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_other.go deleted file mode 100644 index f74b8758d44bb72d27f6b95ebfc835b10503b655..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/conn_other.go +++ /dev/null @@ -1,27 +0,0 @@ -// +build !darwin - -package dbus - -import ( - "bytes" - "errors" - "os/exec" -) - -func sessionBusPlatform() (*Conn, error) { - cmd := exec.Command("dbus-launch") - b, err := cmd.CombinedOutput() - - if err != nil { - return nil, err - } - - i := bytes.IndexByte(b, '=') - j := bytes.IndexByte(b, '\n') - - if i == -1 || j == -1 { - return nil, errors.New("dbus: couldn't determine address of session bus") - } - - return Dial(string(b[i+1 : j])) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/dbus.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/dbus.go deleted file mode 100644 index 2ce68735cdf9250e45b5a871cc9076c4d3d47de5..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/dbus.go +++ /dev/null @@ -1,258 +0,0 @@ -package dbus - -import ( - "errors" - "reflect" - "strings" -) - -var ( - byteType = reflect.TypeOf(byte(0)) - boolType = reflect.TypeOf(false) - uint8Type = reflect.TypeOf(uint8(0)) - int16Type = reflect.TypeOf(int16(0)) - uint16Type = reflect.TypeOf(uint16(0)) - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) - stringType = reflect.TypeOf("") - signatureType = reflect.TypeOf(Signature{""}) - objectPathType = reflect.TypeOf(ObjectPath("")) - variantType = reflect.TypeOf(Variant{Signature{""}, nil}) - interfacesType = reflect.TypeOf([]interface{}{}) - unixFDType = reflect.TypeOf(UnixFD(0)) - unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) -) - -// An InvalidTypeError signals that a value which cannot be represented in the -// D-Bus wire format was passed to a function. -type InvalidTypeError struct { - Type reflect.Type -} - -func (e InvalidTypeError) Error() string { - return "dbus: invalid type " + e.Type.String() -} - -// Store copies the values contained in src to dest, which must be a slice of -// pointers. It converts slices of interfaces from src to corresponding structs -// in dest. An error is returned if the lengths of src and dest or the types of -// their elements don't match. -func Store(src []interface{}, dest ...interface{}) error { - if len(src) != len(dest) { - return errors.New("dbus.Store: length mismatch") - } - - for i := range src { - if err := store(src[i], dest[i]); err != nil { - return err - } - } - return nil -} - -func store(src, dest interface{}) error { - if reflect.TypeOf(dest).Elem() == reflect.TypeOf(src) { - reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src)) - return nil - } else if hasStruct(dest) { - rv := reflect.ValueOf(dest).Elem() - switch rv.Kind() { - case reflect.Struct: - vs, ok := src.([]interface{}) - if !ok { - return errors.New("dbus.Store: type mismatch") - } - t := rv.Type() - ndest := make([]interface{}, 0, rv.NumField()) - for i := 0; i < rv.NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - ndest = append(ndest, rv.Field(i).Addr().Interface()) - } - } - if len(vs) != len(ndest) { - return errors.New("dbus.Store: type mismatch") - } - err := Store(vs, ndest...) - if err != nil { - return errors.New("dbus.Store: type mismatch") - } - case reflect.Slice: - sv := reflect.ValueOf(src) - if sv.Kind() != reflect.Slice { - return errors.New("dbus.Store: type mismatch") - } - rv.Set(reflect.MakeSlice(rv.Type(), sv.Len(), sv.Len())) - for i := 0; i < sv.Len(); i++ { - if err := store(sv.Index(i).Interface(), rv.Index(i).Addr().Interface()); err != nil { - return err - } - } - case reflect.Map: - sv := reflect.ValueOf(src) - if sv.Kind() != reflect.Map { - return errors.New("dbus.Store: type mismatch") - } - keys := sv.MapKeys() - rv.Set(reflect.MakeMap(sv.Type())) - for _, key := range keys { - v := reflect.New(sv.Type().Elem()) - if err := store(v, sv.MapIndex(key).Interface()); err != nil { - return err - } - rv.SetMapIndex(key, v.Elem()) - } - default: - return errors.New("dbus.Store: type mismatch") - } - return nil - } else { - return errors.New("dbus.Store: type mismatch") - } -} - -func hasStruct(v interface{}) bool { - t := reflect.TypeOf(v) - for { - switch t.Kind() { - case reflect.Struct: - return true - case reflect.Slice, reflect.Ptr, reflect.Map: - t = t.Elem() - default: - return false - } - } -} - -// An ObjectPath is an object path as defined by the D-Bus spec. -type ObjectPath string - -// IsValid returns whether the object path is valid. -func (o ObjectPath) IsValid() bool { - s := string(o) - if len(s) == 0 { - return false - } - if s[0] != '/' { - return false - } - if s[len(s)-1] == '/' && len(s) != 1 { - return false - } - // probably not used, but technically possible - if s == "/" { - return true - } - split := strings.Split(s[1:], "/") - for _, v := range split { - if len(v) == 0 { - return false - } - for _, c := range v { - if !isMemberChar(c) { - return false - } - } - } - return true -} - -// A UnixFD is a Unix file descriptor sent over the wire. See the package-level -// documentation for more information about Unix file descriptor passsing. -type UnixFD int32 - -// A UnixFDIndex is the representation of a Unix file descriptor in a message. -type UnixFDIndex uint32 - -// alignment returns the alignment of values of type t. -func alignment(t reflect.Type) int { - switch t { - case variantType: - return 1 - case objectPathType: - return 4 - case signatureType: - return 1 - case interfacesType: // sometimes used for structs - return 8 - } - switch t.Kind() { - case reflect.Uint8: - return 1 - case reflect.Uint16, reflect.Int16: - return 2 - case reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map: - return 4 - case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct: - return 8 - case reflect.Ptr: - return alignment(t.Elem()) - } - return 1 -} - -// isKeyType returns whether t is a valid type for a D-Bus dict. -func isKeyType(t reflect.Type) bool { - switch t.Kind() { - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, - reflect.String: - - return true - } - return false -} - -// isValidInterface returns whether s is a valid name for an interface. -func isValidInterface(s string) bool { - if len(s) == 0 || len(s) > 255 || s[0] == '.' { - return false - } - elem := strings.Split(s, ".") - if len(elem) < 2 { - return false - } - for _, v := range elem { - if len(v) == 0 { - return false - } - if v[0] >= '0' && v[0] <= '9' { - return false - } - for _, c := range v { - if !isMemberChar(c) { - return false - } - } - } - return true -} - -// isValidMember returns whether s is a valid name for a member. -func isValidMember(s string) bool { - if len(s) == 0 || len(s) > 255 { - return false - } - i := strings.Index(s, ".") - if i != -1 { - return false - } - if s[0] >= '0' && s[0] <= '9' { - return false - } - for _, c := range s { - if !isMemberChar(c) { - return false - } - } - return true -} - -func isMemberChar(c rune) bool { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || c == '_' -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/decoder.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/decoder.go deleted file mode 100644 index ef50dcab98d0d8fb1f166b25bd616f50f30b71fc..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/decoder.go +++ /dev/null @@ -1,228 +0,0 @@ -package dbus - -import ( - "encoding/binary" - "io" - "reflect" -) - -type decoder struct { - in io.Reader - order binary.ByteOrder - pos int -} - -// newDecoder returns a new decoder that reads values from in. The input is -// expected to be in the given byte order. -func newDecoder(in io.Reader, order binary.ByteOrder) *decoder { - dec := new(decoder) - dec.in = in - dec.order = order - return dec -} - -// align aligns the input to the given boundary and panics on error. -func (dec *decoder) align(n int) { - if dec.pos%n != 0 { - newpos := (dec.pos + n - 1) & ^(n - 1) - empty := make([]byte, newpos-dec.pos) - if _, err := io.ReadFull(dec.in, empty); err != nil { - panic(err) - } - dec.pos = newpos - } -} - -// Calls binary.Read(dec.in, dec.order, v) and panics on read errors. -func (dec *decoder) binread(v interface{}) { - if err := binary.Read(dec.in, dec.order, v); err != nil { - panic(err) - } -} - -func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) { - defer func() { - var ok bool - v := recover() - if err, ok = v.(error); ok { - if err == io.EOF || err == io.ErrUnexpectedEOF { - err = FormatError("unexpected EOF") - } - } - }() - vs = make([]interface{}, 0) - s := sig.str - for s != "" { - err, rem := validSingle(s, 0) - if err != nil { - return nil, err - } - v := dec.decode(s[:len(s)-len(rem)], 0) - vs = append(vs, v) - s = rem - } - return vs, nil -} - -func (dec *decoder) decode(s string, depth int) interface{} { - dec.align(alignment(typeFor(s))) - switch s[0] { - case 'y': - var b [1]byte - if _, err := dec.in.Read(b[:]); err != nil { - panic(err) - } - dec.pos++ - return b[0] - case 'b': - i := dec.decode("u", depth).(uint32) - switch { - case i == 0: - return false - case i == 1: - return true - default: - panic(FormatError("invalid value for boolean")) - } - case 'n': - var i int16 - dec.binread(&i) - dec.pos += 2 - return i - case 'i': - var i int32 - dec.binread(&i) - dec.pos += 4 - return i - case 'x': - var i int64 - dec.binread(&i) - dec.pos += 8 - return i - case 'q': - var i uint16 - dec.binread(&i) - dec.pos += 2 - return i - case 'u': - var i uint32 - dec.binread(&i) - dec.pos += 4 - return i - case 't': - var i uint64 - dec.binread(&i) - dec.pos += 8 - return i - case 'd': - var f float64 - dec.binread(&f) - dec.pos += 8 - return f - case 's': - length := dec.decode("u", depth).(uint32) - b := make([]byte, int(length)+1) - if _, err := io.ReadFull(dec.in, b); err != nil { - panic(err) - } - dec.pos += int(length) + 1 - return string(b[:len(b)-1]) - case 'o': - return ObjectPath(dec.decode("s", depth).(string)) - case 'g': - length := dec.decode("y", depth).(byte) - b := make([]byte, int(length)+1) - if _, err := io.ReadFull(dec.in, b); err != nil { - panic(err) - } - dec.pos += int(length) + 1 - sig, err := ParseSignature(string(b[:len(b)-1])) - if err != nil { - panic(err) - } - return sig - case 'v': - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - var variant Variant - sig := dec.decode("g", depth).(Signature) - if len(sig.str) == 0 { - panic(FormatError("variant signature is empty")) - } - err, rem := validSingle(sig.str, 0) - if err != nil { - panic(err) - } - if rem != "" { - panic(FormatError("variant signature has multiple types")) - } - variant.sig = sig - variant.value = dec.decode(sig.str, depth+1) - return variant - case 'h': - return UnixFDIndex(dec.decode("u", depth).(uint32)) - case 'a': - if len(s) > 1 && s[1] == '{' { - ksig := s[2:3] - vsig := s[3 : len(s)-1] - v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig))) - if depth >= 63 { - panic(FormatError("input exceeds container depth limit")) - } - length := dec.decode("u", depth).(uint32) - // Even for empty maps, the correct padding must be included - dec.align(8) - spos := dec.pos - for dec.pos < spos+int(length) { - dec.align(8) - if !isKeyType(v.Type().Key()) { - panic(InvalidTypeError{v.Type()}) - } - kv := dec.decode(ksig, depth+2) - vv := dec.decode(vsig, depth+2) - v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) - } - return v.Interface() - } - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - length := dec.decode("u", depth).(uint32) - v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) - // Even for empty arrays, the correct padding must be included - dec.align(alignment(typeFor(s[1:]))) - spos := dec.pos - for dec.pos < spos+int(length) { - ev := dec.decode(s[1:], depth+1) - v = reflect.Append(v, reflect.ValueOf(ev)) - } - return v.Interface() - case '(': - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - dec.align(8) - v := make([]interface{}, 0) - s = s[1 : len(s)-1] - for s != "" { - err, rem := validSingle(s, 0) - if err != nil { - panic(err) - } - ev := dec.decode(s[:len(s)-len(rem)], depth+1) - v = append(v, ev) - s = rem - } - return v - default: - panic(SignatureError{Sig: s}) - } -} - -// A FormatError is an error in the wire format. -type FormatError string - -func (e FormatError) Error() string { - return "dbus: wire format error: " + string(e) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/doc.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/doc.go deleted file mode 100644 index deff554a381ad3baefb767a161bf77ca65f59934..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/doc.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Package dbus implements bindings to the D-Bus message bus system. - -To use the message bus API, you first need to connect to a bus (usually the -session or system bus). The acquired connection then can be used to call methods -on remote objects and emit or receive signals. Using the Export method, you can -arrange D-Bus methods calls to be directly translated to method calls on a Go -value. - -Conversion Rules - -For outgoing messages, Go types are automatically converted to the -corresponding D-Bus types. The following types are directly encoded as their -respective D-Bus equivalents: - - Go type | D-Bus type - ------------+----------- - byte | BYTE - bool | BOOLEAN - int16 | INT16 - uint16 | UINT16 - int32 | INT32 - uint32 | UINT32 - int64 | INT64 - uint64 | UINT64 - float64 | DOUBLE - string | STRING - ObjectPath | OBJECT_PATH - Signature | SIGNATURE - Variant | VARIANT - UnixFDIndex | UNIX_FD - -Slices and arrays encode as ARRAYs of their element type. - -Maps encode as DICTs, provided that their key type can be used as a key for -a DICT. - -Structs other than Variant and Signature encode as a STRUCT containing their -exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will -be skipped. - -Pointers encode as the value they're pointed to. - -Trying to encode any other type or a slice, map or struct containing an -unsupported type will result in an InvalidTypeError. - -For incoming messages, the inverse of these rules are used, with the exception -of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces -containing the struct fields in the correct order. The Store function can be -used to convert such values to Go structs. - -Unix FD passing - -Handling Unix file descriptors deserves special mention. To use them, you should -first check that they are supported on a connection by calling SupportsUnixFDs. -If it returns true, all method of Connection will translate messages containing -UnixFD's to messages that are accompanied by the given file descriptors with the -UnixFD values being substituted by the correct indices. Similarily, the indices -of incoming messages are automatically resolved. It shouldn't be necessary to use -UnixFDIndex. - -*/ -package dbus diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go deleted file mode 100644 index 9f0a9e89eabfe73e961de2d616424056ed77750d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/encoder.go +++ /dev/null @@ -1,208 +0,0 @@ -package dbus - -import ( - "bytes" - "encoding/binary" - "io" - "reflect" -) - -// An encoder encodes values to the D-Bus wire format. -type encoder struct { - out io.Writer - order binary.ByteOrder - pos int -} - -// NewEncoder returns a new encoder that writes to out in the given byte order. -func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { - return newEncoderAtOffset(out, 0, order) -} - -// newEncoderAtOffset returns a new encoder that writes to out in the given -// byte order. Specify the offset to initialize pos for proper alignment -// computation. -func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { - enc := new(encoder) - enc.out = out - enc.order = order - enc.pos = offset - return enc -} - -// Aligns the next output to be on a multiple of n. Panics on write errors. -func (enc *encoder) align(n int) { - pad := enc.padding(0, n) - if pad > 0 { - empty := make([]byte, pad) - if _, err := enc.out.Write(empty); err != nil { - panic(err) - } - enc.pos += pad - } -} - -// pad returns the number of bytes of padding, based on current position and additional offset. -// and alignment. -func (enc *encoder) padding(offset, algn int) int { - abs := enc.pos + offset - if abs%algn != 0 { - newabs := (abs + algn - 1) & ^(algn - 1) - return newabs - abs - } - return 0 -} - -// Calls binary.Write(enc.out, enc.order, v) and panics on write errors. -func (enc *encoder) binwrite(v interface{}) { - if err := binary.Write(enc.out, enc.order, v); err != nil { - panic(err) - } -} - -// Encode encodes the given values to the underyling reader. All written values -// are aligned properly as required by the D-Bus spec. -func (enc *encoder) Encode(vs ...interface{}) (err error) { - defer func() { - err, _ = recover().(error) - }() - for _, v := range vs { - enc.encode(reflect.ValueOf(v), 0) - } - return nil -} - -// encode encodes the given value to the writer and panics on error. depth holds -// the depth of the container nesting. -func (enc *encoder) encode(v reflect.Value, depth int) { - enc.align(alignment(v.Type())) - switch v.Kind() { - case reflect.Uint8: - var b [1]byte - b[0] = byte(v.Uint()) - if _, err := enc.out.Write(b[:]); err != nil { - panic(err) - } - enc.pos++ - case reflect.Bool: - if v.Bool() { - enc.encode(reflect.ValueOf(uint32(1)), depth) - } else { - enc.encode(reflect.ValueOf(uint32(0)), depth) - } - case reflect.Int16: - enc.binwrite(int16(v.Int())) - enc.pos += 2 - case reflect.Uint16: - enc.binwrite(uint16(v.Uint())) - enc.pos += 2 - case reflect.Int32: - enc.binwrite(int32(v.Int())) - enc.pos += 4 - case reflect.Uint32: - enc.binwrite(uint32(v.Uint())) - enc.pos += 4 - case reflect.Int64: - enc.binwrite(v.Int()) - enc.pos += 8 - case reflect.Uint64: - enc.binwrite(v.Uint()) - enc.pos += 8 - case reflect.Float64: - enc.binwrite(v.Float()) - enc.pos += 8 - case reflect.String: - enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth) - b := make([]byte, v.Len()+1) - copy(b, v.String()) - b[len(b)-1] = 0 - n, err := enc.out.Write(b) - if err != nil { - panic(err) - } - enc.pos += n - case reflect.Ptr: - enc.encode(v.Elem(), depth) - case reflect.Slice, reflect.Array: - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - // Lookahead offset: 4 bytes for uint32 length (with alignment), - // plus alignment for elements. - n := enc.padding(0, 4) + 4 - offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) - - var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) - - for i := 0; i < v.Len(); i++ { - bufenc.encode(v.Index(i), depth+1) - } - enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) - length := buf.Len() - enc.align(alignment(v.Type().Elem())) - if _, err := buf.WriteTo(enc.out); err != nil { - panic(err) - } - enc.pos += length - case reflect.Struct: - if depth >= 64 && v.Type() != signatureType { - panic(FormatError("input exceeds container depth limit")) - } - switch t := v.Type(); t { - case signatureType: - str := v.Field(0) - enc.encode(reflect.ValueOf(byte(str.Len())), depth+1) - b := make([]byte, str.Len()+1) - copy(b, str.String()) - b[len(b)-1] = 0 - n, err := enc.out.Write(b) - if err != nil { - panic(err) - } - enc.pos += n - case variantType: - variant := v.Interface().(Variant) - enc.encode(reflect.ValueOf(variant.sig), depth+1) - enc.encode(reflect.ValueOf(variant.value), depth+1) - default: - for i := 0; i < v.Type().NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - enc.encode(v.Field(i), depth+1) - } - } - } - case reflect.Map: - // Maps are arrays of structures, so they actually increase the depth by - // 2. - if depth >= 63 { - panic(FormatError("input exceeds container depth limit")) - } - if !isKeyType(v.Type().Key()) { - panic(InvalidTypeError{v.Type()}) - } - keys := v.MapKeys() - // Lookahead offset: 4 bytes for uint32 length (with alignment), - // plus 8-byte alignment - n := enc.padding(0, 4) + 4 - offset := enc.pos + n + enc.padding(n, 8) - - var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) - for _, k := range keys { - bufenc.align(8) - bufenc.encode(k, depth+2) - bufenc.encode(v.MapIndex(k), depth+2) - } - enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) - length := buf.Len() - enc.align(8) - if _, err := buf.WriteTo(enc.out); err != nil { - panic(err) - } - enc.pos += length - default: - panic(InvalidTypeError{v.Type()}) - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/export.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/export.go deleted file mode 100644 index c6440a7416a02248af76dc5b9c5e454d68bac26f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/export.go +++ /dev/null @@ -1,411 +0,0 @@ -package dbus - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -var ( - errmsgInvalidArg = Error{ - "org.freedesktop.DBus.Error.InvalidArgs", - []interface{}{"Invalid type / number of args"}, - } - errmsgNoObject = Error{ - "org.freedesktop.DBus.Error.NoSuchObject", - []interface{}{"No such object"}, - } - errmsgUnknownMethod = Error{ - "org.freedesktop.DBus.Error.UnknownMethod", - []interface{}{"Unknown / invalid method"}, - } -) - -// exportWithMapping represents an exported struct along with a method name -// mapping to allow for exporting lower-case methods, etc. -type exportWithMapping struct { - export interface{} - - // Method name mapping; key -> struct method, value -> dbus method. - mapping map[string]string - - // Whether or not this export is for the entire subtree - includeSubtree bool -} - -// Sender is a type which can be used in exported methods to receive the message -// sender. -type Sender string - -func exportedMethod(export exportWithMapping, name string) reflect.Value { - if export.export == nil { - return reflect.Value{} - } - - // If a mapping was included in the export, check the map to see if we - // should be looking for a different method in the export. - if export.mapping != nil { - for key, value := range export.mapping { - if value == name { - name = key - break - } - - // Catch the case where a method is aliased but the client is calling - // the original, e.g. the "Foo" method was exported mapped to - // "foo," and dbus client called the original "Foo." - if key == name { - return reflect.Value{} - } - } - } - - value := reflect.ValueOf(export.export) - m := value.MethodByName(name) - - // Catch the case of attempting to call an unexported method - method, ok := value.Type().MethodByName(name) - - if !m.IsValid() || !ok || method.PkgPath != "" { - return reflect.Value{} - } - t := m.Type() - if t.NumOut() == 0 || - t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) { - - return reflect.Value{} - } - return m -} - -// searchHandlers will look through all registered handlers looking for one -// to handle the given path. If a verbatim one isn't found, it will check for -// a subtree registration for the path as well. -func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) { - conn.handlersLck.RLock() - defer conn.handlersLck.RUnlock() - - handlers, ok := conn.handlers[path] - if ok { - return handlers, ok - } - - // If handlers weren't found for this exact path, look for a matching subtree - // registration - handlers = make(map[string]exportWithMapping) - path = path[:strings.LastIndex(string(path), "/")] - for len(path) > 0 { - var subtreeHandlers map[string]exportWithMapping - subtreeHandlers, ok = conn.handlers[path] - if ok { - for iface, handler := range subtreeHandlers { - // Only include this handler if it registered for the subtree - if handler.includeSubtree { - handlers[iface] = handler - } - } - - break - } - - path = path[:strings.LastIndex(string(path), "/")] - } - - return handlers, ok -} - -// handleCall handles the given method call (i.e. looks if it's one of the -// pre-implemented ones and searches for a corresponding handler if not). -func (conn *Conn) handleCall(msg *Message) { - name := msg.Headers[FieldMember].value.(string) - path := msg.Headers[FieldPath].value.(ObjectPath) - ifaceName, hasIface := msg.Headers[FieldInterface].value.(string) - sender, hasSender := msg.Headers[FieldSender].value.(string) - serial := msg.serial - if ifaceName == "org.freedesktop.DBus.Peer" { - switch name { - case "Ping": - conn.sendReply(sender, serial) - case "GetMachineId": - conn.sendReply(sender, serial, conn.uuid) - default: - conn.sendError(errmsgUnknownMethod, sender, serial) - } - return - } - if len(name) == 0 { - conn.sendError(errmsgUnknownMethod, sender, serial) - } - - // Find the exported handler (if any) for this path - handlers, ok := conn.searchHandlers(path) - if !ok { - conn.sendError(errmsgNoObject, sender, serial) - return - } - - var m reflect.Value - if hasIface { - iface := handlers[ifaceName] - m = exportedMethod(iface, name) - } else { - for _, v := range handlers { - m = exportedMethod(v, name) - if m.IsValid() { - break - } - } - } - - if !m.IsValid() { - conn.sendError(errmsgUnknownMethod, sender, serial) - return - } - - t := m.Type() - vs := msg.Body - pointers := make([]interface{}, t.NumIn()) - decode := make([]interface{}, 0, len(vs)) - for i := 0; i < t.NumIn(); i++ { - tp := t.In(i) - val := reflect.New(tp) - pointers[i] = val.Interface() - if tp == reflect.TypeOf((*Sender)(nil)).Elem() { - val.Elem().SetString(sender) - } else if tp == reflect.TypeOf((*Message)(nil)).Elem() { - val.Elem().Set(reflect.ValueOf(*msg)) - } else { - decode = append(decode, pointers[i]) - } - } - - if len(decode) != len(vs) { - conn.sendError(errmsgInvalidArg, sender, serial) - return - } - - if err := Store(vs, decode...); err != nil { - conn.sendError(errmsgInvalidArg, sender, serial) - return - } - - // Extract parameters - params := make([]reflect.Value, len(pointers)) - for i := 0; i < len(pointers); i++ { - params[i] = reflect.ValueOf(pointers[i]).Elem() - } - - // Call method - ret := m.Call(params) - if em := ret[t.NumOut()-1].Interface().(*Error); em != nil { - conn.sendError(*em, sender, serial) - return - } - - if msg.Flags&FlagNoReplyExpected == 0 { - reply := new(Message) - reply.Type = TypeMethodReply - reply.serial = conn.getSerial() - reply.Headers = make(map[HeaderField]Variant) - if hasSender { - reply.Headers[FieldDestination] = msg.Headers[FieldSender] - } - reply.Headers[FieldReplySerial] = MakeVariant(msg.serial) - reply.Body = make([]interface{}, len(ret)-1) - for i := 0; i < len(ret)-1; i++ { - reply.Body[i] = ret[i].Interface() - } - if len(ret) != 1 { - reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- reply - } - conn.outLck.RUnlock() - } -} - -// Emit emits the given signal on the message bus. The name parameter must be -// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost". -func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error { - if !path.IsValid() { - return errors.New("dbus: invalid object path") - } - i := strings.LastIndex(name, ".") - if i == -1 { - return errors.New("dbus: invalid method name") - } - iface := name[:i] - member := name[i+1:] - if !isValidMember(member) { - return errors.New("dbus: invalid method name") - } - if !isValidInterface(iface) { - return errors.New("dbus: invalid interface name") - } - msg := new(Message) - msg.Type = TypeSignal - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldInterface] = MakeVariant(iface) - msg.Headers[FieldMember] = MakeVariant(member) - msg.Headers[FieldPath] = MakeVariant(path) - msg.Body = values - if len(values) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) - } - conn.outLck.RLock() - defer conn.outLck.RUnlock() - if conn.closed { - return ErrClosed - } - conn.out <- msg - return nil -} - -// Export registers the given value to be exported as an object on the -// message bus. -// -// If a method call on the given path and interface is received, an exported -// method with the same name is called with v as the receiver if the -// parameters match and the last return value is of type *Error. If this -// *Error is not nil, it is sent back to the caller as an error. -// Otherwise, a method reply is sent with the other return values as its body. -// -// Any parameters with the special type Sender are set to the sender of the -// dbus message when the method is called. Parameters of this type do not -// contribute to the dbus signature of the method (i.e. the method is exposed -// as if the parameters of type Sender were not there). -// -// Similarly, any parameters with the type Message are set to the raw message -// received on the bus. Again, parameters of this type do not contribute to the -// dbus signature of the method. -// -// Every method call is executed in a new goroutine, so the method may be called -// in multiple goroutines at once. -// -// Method calls on the interface org.freedesktop.DBus.Peer will be automatically -// handled for every object. -// -// Passing nil as the first parameter will cause conn to cease handling calls on -// the given combination of path and interface. -// -// Export returns an error if path is not a valid path name. -func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { - return conn.ExportWithMap(v, nil, path, iface) -} - -// ExportWithMap works exactly like Export but provides the ability to remap -// method names (e.g. export a lower-case method). -// -// The keys in the map are the real method names (exported on the struct), and -// the values are the method names to be exported on DBus. -func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { - return conn.exportWithMap(v, mapping, path, iface, false) -} - -// ExportSubtree works exactly like Export but registers the given value for -// an entire subtree rather under the root path provided. -// -// In order to make this useful, one parameter in each of the value's exported -// methods should be a Message, in which case it will contain the raw message -// (allowing one to get access to the path that caused the method to be called). -// -// Note that more specific export paths take precedence over less specific. For -// example, a method call using the ObjectPath /foo/bar/baz will call a method -// exported on /foo/bar before a method exported on /foo. -func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error { - return conn.ExportSubtreeWithMap(v, nil, path, iface) -} - -// ExportSubtreeWithMap works exactly like ExportSubtree but provides the -// ability to remap method names (e.g. export a lower-case method). -// -// The keys in the map are the real method names (exported on the struct), and -// the values are the method names to be exported on DBus. -func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { - return conn.exportWithMap(v, mapping, path, iface, true) -} - -// exportWithMap is the worker function for all exports/registrations. -func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error { - if !path.IsValid() { - return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) - } - - conn.handlersLck.Lock() - defer conn.handlersLck.Unlock() - - // Remove a previous export if the interface is nil - if v == nil { - if _, ok := conn.handlers[path]; ok { - delete(conn.handlers[path], iface) - if len(conn.handlers[path]) == 0 { - delete(conn.handlers, path) - } - } - - return nil - } - - // If this is the first handler for this path, make a new map to hold all - // handlers for this path. - if _, ok := conn.handlers[path]; !ok { - conn.handlers[path] = make(map[string]exportWithMapping) - } - - // Finally, save this handler - conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree} - - return nil -} - -// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response. -func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) { - var r uint32 - err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r) - if err != nil { - return 0, err - } - return ReleaseNameReply(r), nil -} - -// RequestName calls org.freedesktop.DBus.RequestName and awaits a response. -func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) { - var r uint32 - err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r) - if err != nil { - return 0, err - } - return RequestNameReply(r), nil -} - -// ReleaseNameReply is the reply to a ReleaseName call. -type ReleaseNameReply uint32 - -const ( - ReleaseNameReplyReleased ReleaseNameReply = 1 + iota - ReleaseNameReplyNonExistent - ReleaseNameReplyNotOwner -) - -// RequestNameFlags represents the possible flags for a RequestName call. -type RequestNameFlags uint32 - -const ( - NameFlagAllowReplacement RequestNameFlags = 1 << iota - NameFlagReplaceExisting - NameFlagDoNotQueue -) - -// RequestNameReply is the reply to a RequestName call. -type RequestNameReply uint32 - -const ( - RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota - RequestNameReplyInQueue - RequestNameReplyExists - RequestNameReplyAlreadyOwner -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir.go deleted file mode 100644 index 0b745f9313a4aeb8f6bcb9746d45fdeeedf0524f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir.go +++ /dev/null @@ -1,28 +0,0 @@ -package dbus - -import ( - "os" - "sync" -) - -var ( - homeDir string - homeDirLock sync.Mutex -) - -func getHomeDir() string { - homeDirLock.Lock() - defer homeDirLock.Unlock() - - if homeDir != "" { - return homeDir - } - - homeDir = os.Getenv("HOME") - if homeDir != "" { - return homeDir - } - - homeDir = lookupHomeDir() - return homeDir -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_dynamic.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_dynamic.go deleted file mode 100644 index 2732081e73b47367d4f084a62dfe3e56d33906bb..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_dynamic.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !static_build - -package dbus - -import ( - "os/user" -) - -func lookupHomeDir() string { - u, err := user.Current() - if err != nil { - return "/" - } - return u.HomeDir -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_static.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_static.go deleted file mode 100644 index b9d9cb5525a397feb0214f077afbc24d790a3280..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/homedir_static.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build static_build - -package dbus - -import ( - "bufio" - "os" - "strconv" - "strings" -) - -func lookupHomeDir() string { - myUid := os.Getuid() - - f, err := os.Open("/etc/passwd") - if err != nil { - return "/" - } - defer f.Close() - - s := bufio.NewScanner(f) - - for s.Scan() { - if err := s.Err(); err != nil { - break - } - - line := strings.TrimSpace(s.Text()) - if line == "" { - continue - } - - parts := strings.Split(line, ":") - - if len(parts) >= 6 { - uid, err := strconv.Atoi(parts[2]) - if err == nil && uid == myUid { - return parts[5] - } - } - } - - // Default to / if we can't get a better value - return "/" -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go deleted file mode 100644 index 790a23ec2404602569485915c7b3a2007fc6fd8a..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/call.go +++ /dev/null @@ -1,27 +0,0 @@ -package introspect - -import ( - "encoding/xml" - "github.com/godbus/dbus" - "strings" -) - -// Call calls org.freedesktop.Introspectable.Introspect on a remote object -// and returns the introspection data. -func Call(o dbus.BusObject) (*Node, error) { - var xmldata string - var node Node - - err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata) - if err != nil { - return nil, err - } - err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node) - if err != nil { - return nil, err - } - if node.Name == "" { - node.Name = string(o.Path()) - } - return &node, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspect.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspect.go deleted file mode 100644 index b06c3f1cf2d08f49f06ace8fc1f940d783ba33fe..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspect.go +++ /dev/null @@ -1,86 +0,0 @@ -// Package introspect provides some utilities for dealing with the DBus -// introspection format. -package introspect - -import "encoding/xml" - -// The introspection data for the org.freedesktop.DBus.Introspectable interface. -var IntrospectData = Interface{ - Name: "org.freedesktop.DBus.Introspectable", - Methods: []Method{ - { - Name: "Introspect", - Args: []Arg{ - {"out", "s", "out"}, - }, - }, - }, -} - -// XML document type declaration of the introspection format version 1.0 -const IntrospectDeclarationString = ` - <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" - "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> -` - -// The introspection data for the org.freedesktop.DBus.Introspectable interface, -// as a string. -const IntrospectDataString = ` - <interface name="org.freedesktop.DBus.Introspectable"> - <method name="Introspect"> - <arg name="out" direction="out" type="s"/> - </method> - </interface> -` - -// Node is the root element of an introspection. -type Node struct { - XMLName xml.Name `xml:"node"` - Name string `xml:"name,attr,omitempty"` - Interfaces []Interface `xml:"interface"` - Children []Node `xml:"node,omitempty"` -} - -// Interface describes a DBus interface that is available on the message bus. -type Interface struct { - Name string `xml:"name,attr"` - Methods []Method `xml:"method"` - Signals []Signal `xml:"signal"` - Properties []Property `xml:"property"` - Annotations []Annotation `xml:"annotation"` -} - -// Method describes a Method on an Interface as retured by an introspection. -type Method struct { - Name string `xml:"name,attr"` - Args []Arg `xml:"arg"` - Annotations []Annotation `xml:"annotation"` -} - -// Signal describes a Signal emitted on an Interface. -type Signal struct { - Name string `xml:"name,attr"` - Args []Arg `xml:"arg"` - Annotations []Annotation `xml:"annotation"` -} - -// Property describes a property of an Interface. -type Property struct { - Name string `xml:"name,attr"` - Type string `xml:"type,attr"` - Access string `xml:"access,attr"` - Annotations []Annotation `xml:"annotation"` -} - -// Arg represents an argument of a method or a signal. -type Arg struct { - Name string `xml:"name,attr,omitempty"` - Type string `xml:"type,attr"` - Direction string `xml:"direction,attr,omitempty"` -} - -// Annotation is an annotation in the introspection format. -type Annotation struct { - Name string `xml:"name,attr"` - Value string `xml:"value,attr"` -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go deleted file mode 100644 index 2f16690b99cc4e143703753053d991df00eb4b78..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/introspect/introspectable.go +++ /dev/null @@ -1,76 +0,0 @@ -package introspect - -import ( - "encoding/xml" - "github.com/godbus/dbus" - "reflect" - "strings" -) - -// Introspectable implements org.freedesktop.Introspectable. -// -// You can create it by converting the XML-formatted introspection data from a -// string to an Introspectable or call NewIntrospectable with a Node. Then, -// export it as org.freedesktop.Introspectable on you object. -type Introspectable string - -// NewIntrospectable returns an Introspectable that returns the introspection -// data that corresponds to the given Node. If n.Interfaces doesn't contain the -// data for org.freedesktop.DBus.Introspectable, it is added automatically. -func NewIntrospectable(n *Node) Introspectable { - found := false - for _, v := range n.Interfaces { - if v.Name == "org.freedesktop.DBus.Introspectable" { - found = true - break - } - } - if !found { - n.Interfaces = append(n.Interfaces, IntrospectData) - } - b, err := xml.Marshal(n) - if err != nil { - panic(err) - } - return Introspectable(strings.TrimSpace(IntrospectDeclarationString) + string(b)) -} - -// Introspect implements org.freedesktop.Introspectable.Introspect. -func (i Introspectable) Introspect() (string, *dbus.Error) { - return string(i), nil -} - -// Methods returns the description of the methods of v. This can be used to -// create a Node which can be passed to NewIntrospectable. -func Methods(v interface{}) []Method { - t := reflect.TypeOf(v) - ms := make([]Method, 0, t.NumMethod()) - for i := 0; i < t.NumMethod(); i++ { - if t.Method(i).PkgPath != "" { - continue - } - mt := t.Method(i).Type - if mt.NumOut() == 0 || - mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{}) { - - continue - } - var m Method - m.Name = t.Method(i).Name - m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2) - for j := 1; j < mt.NumIn(); j++ { - if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() && - mt.In(j) != reflect.TypeOf((*dbus.Message)(nil)).Elem() { - arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"} - m.Args = append(m.Args, arg) - } - } - for j := 0; j < mt.NumOut()-1; j++ { - arg := Arg{"", dbus.SignatureOfType(mt.Out(j)).String(), "out"} - m.Args = append(m.Args, arg) - } - m.Annotations = make([]Annotation, 0) - ms = append(ms, m) - } - return ms -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/message.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/message.go deleted file mode 100644 index 075d6e38baee960c3a35122d9dff74681f7c2776..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/message.go +++ /dev/null @@ -1,346 +0,0 @@ -package dbus - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "reflect" - "strconv" -) - -const protoVersion byte = 1 - -// Flags represents the possible flags of a D-Bus message. -type Flags byte - -const ( - // FlagNoReplyExpected signals that the message is not expected to generate - // a reply. If this flag is set on outgoing messages, any possible reply - // will be discarded. - FlagNoReplyExpected Flags = 1 << iota - // FlagNoAutoStart signals that the message bus should not automatically - // start an application when handling this message. - FlagNoAutoStart -) - -// Type represents the possible types of a D-Bus message. -type Type byte - -const ( - TypeMethodCall Type = 1 + iota - TypeMethodReply - TypeError - TypeSignal - typeMax -) - -func (t Type) String() string { - switch t { - case TypeMethodCall: - return "method call" - case TypeMethodReply: - return "reply" - case TypeError: - return "error" - case TypeSignal: - return "signal" - } - return "invalid" -} - -// HeaderField represents the possible byte codes for the headers -// of a D-Bus message. -type HeaderField byte - -const ( - FieldPath HeaderField = 1 + iota - FieldInterface - FieldMember - FieldErrorName - FieldReplySerial - FieldDestination - FieldSender - FieldSignature - FieldUnixFDs - fieldMax -) - -// An InvalidMessageError describes the reason why a D-Bus message is regarded as -// invalid. -type InvalidMessageError string - -func (e InvalidMessageError) Error() string { - return "dbus: invalid message: " + string(e) -} - -// fieldType are the types of the various header fields. -var fieldTypes = [fieldMax]reflect.Type{ - FieldPath: objectPathType, - FieldInterface: stringType, - FieldMember: stringType, - FieldErrorName: stringType, - FieldReplySerial: uint32Type, - FieldDestination: stringType, - FieldSender: stringType, - FieldSignature: signatureType, - FieldUnixFDs: uint32Type, -} - -// requiredFields lists the header fields that are required by the different -// message types. -var requiredFields = [typeMax][]HeaderField{ - TypeMethodCall: {FieldPath, FieldMember}, - TypeMethodReply: {FieldReplySerial}, - TypeError: {FieldErrorName, FieldReplySerial}, - TypeSignal: {FieldPath, FieldInterface, FieldMember}, -} - -// Message represents a single D-Bus message. -type Message struct { - Type - Flags - Headers map[HeaderField]Variant - Body []interface{} - - serial uint32 -} - -type header struct { - Field byte - Variant -} - -// DecodeMessage tries to decode a single message in the D-Bus wire format -// from the given reader. The byte order is figured out from the first byte. -// The possibly returned error can be an error of the underlying reader, an -// InvalidMessageError or a FormatError. -func DecodeMessage(rd io.Reader) (msg *Message, err error) { - var order binary.ByteOrder - var hlength, length uint32 - var typ, flags, proto byte - var headers []header - - b := make([]byte, 1) - _, err = rd.Read(b) - if err != nil { - return - } - switch b[0] { - case 'l': - order = binary.LittleEndian - case 'B': - order = binary.BigEndian - default: - return nil, InvalidMessageError("invalid byte order") - } - - dec := newDecoder(rd, order) - dec.pos = 1 - - msg = new(Message) - vs, err := dec.Decode(Signature{"yyyuu"}) - if err != nil { - return nil, err - } - if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil { - return nil, err - } - msg.Type = Type(typ) - msg.Flags = Flags(flags) - - // get the header length separately because we need it later - b = make([]byte, 4) - _, err = io.ReadFull(rd, b) - if err != nil { - return nil, err - } - binary.Read(bytes.NewBuffer(b), order, &hlength) - if hlength+length+16 > 1<<27 { - return nil, InvalidMessageError("message is too long") - } - dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order) - dec.pos = 12 - vs, err = dec.Decode(Signature{"a(yv)"}) - if err != nil { - return nil, err - } - if err = Store(vs, &headers); err != nil { - return nil, err - } - - msg.Headers = make(map[HeaderField]Variant) - for _, v := range headers { - msg.Headers[HeaderField(v.Field)] = v.Variant - } - - dec.align(8) - body := make([]byte, int(length)) - if length != 0 { - _, err := io.ReadFull(rd, body) - if err != nil { - return nil, err - } - } - - if err = msg.IsValid(); err != nil { - return nil, err - } - sig, _ := msg.Headers[FieldSignature].value.(Signature) - if sig.str != "" { - buf := bytes.NewBuffer(body) - dec = newDecoder(buf, order) - vs, err := dec.Decode(sig) - if err != nil { - return nil, err - } - msg.Body = vs - } - - return -} - -// EncodeTo encodes and sends a message to the given writer. The byte order must -// be either binary.LittleEndian or binary.BigEndian. If the message is not -// valid or an error occurs when writing, an error is returned. -func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { - if err := msg.IsValid(); err != nil { - return err - } - var vs [7]interface{} - switch order { - case binary.LittleEndian: - vs[0] = byte('l') - case binary.BigEndian: - vs[0] = byte('B') - default: - return errors.New("dbus: invalid byte order") - } - body := new(bytes.Buffer) - enc := newEncoder(body, order) - if len(msg.Body) != 0 { - enc.Encode(msg.Body...) - } - vs[1] = msg.Type - vs[2] = msg.Flags - vs[3] = protoVersion - vs[4] = uint32(len(body.Bytes())) - vs[5] = msg.serial - headers := make([]header, 0, len(msg.Headers)) - for k, v := range msg.Headers { - headers = append(headers, header{byte(k), v}) - } - vs[6] = headers - var buf bytes.Buffer - enc = newEncoder(&buf, order) - enc.Encode(vs[:]...) - enc.align(8) - body.WriteTo(&buf) - if buf.Len() > 1<<27 { - return InvalidMessageError("message is too long") - } - if _, err := buf.WriteTo(out); err != nil { - return err - } - return nil -} - -// IsValid checks whether msg is a valid message and returns an -// InvalidMessageError if it is not. -func (msg *Message) IsValid() error { - if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected) != 0 { - return InvalidMessageError("invalid flags") - } - if msg.Type == 0 || msg.Type >= typeMax { - return InvalidMessageError("invalid message type") - } - for k, v := range msg.Headers { - if k == 0 || k >= fieldMax { - return InvalidMessageError("invalid header") - } - if reflect.TypeOf(v.value) != fieldTypes[k] { - return InvalidMessageError("invalid type of header field") - } - } - for _, v := range requiredFields[msg.Type] { - if _, ok := msg.Headers[v]; !ok { - return InvalidMessageError("missing required header") - } - } - if path, ok := msg.Headers[FieldPath]; ok { - if !path.value.(ObjectPath).IsValid() { - return InvalidMessageError("invalid path name") - } - } - if iface, ok := msg.Headers[FieldInterface]; ok { - if !isValidInterface(iface.value.(string)) { - return InvalidMessageError("invalid interface name") - } - } - if member, ok := msg.Headers[FieldMember]; ok { - if !isValidMember(member.value.(string)) { - return InvalidMessageError("invalid member name") - } - } - if errname, ok := msg.Headers[FieldErrorName]; ok { - if !isValidInterface(errname.value.(string)) { - return InvalidMessageError("invalid error name") - } - } - if len(msg.Body) != 0 { - if _, ok := msg.Headers[FieldSignature]; !ok { - return InvalidMessageError("missing signature") - } - } - return nil -} - -// Serial returns the message's serial number. The returned value is only valid -// for messages received by eavesdropping. -func (msg *Message) Serial() uint32 { - return msg.serial -} - -// String returns a string representation of a message similar to the format of -// dbus-monitor. -func (msg *Message) String() string { - if err := msg.IsValid(); err != nil { - return "<invalid>" - } - s := msg.Type.String() - if v, ok := msg.Headers[FieldSender]; ok { - s += " from " + v.value.(string) - } - if v, ok := msg.Headers[FieldDestination]; ok { - s += " to " + v.value.(string) - } - s += " serial " + strconv.FormatUint(uint64(msg.serial), 10) - if v, ok := msg.Headers[FieldReplySerial]; ok { - s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10) - } - if v, ok := msg.Headers[FieldUnixFDs]; ok { - s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10) - } - if v, ok := msg.Headers[FieldPath]; ok { - s += " path " + string(v.value.(ObjectPath)) - } - if v, ok := msg.Headers[FieldInterface]; ok { - s += " interface " + v.value.(string) - } - if v, ok := msg.Headers[FieldErrorName]; ok { - s += " error " + v.value.(string) - } - if v, ok := msg.Headers[FieldMember]; ok { - s += " member " + v.value.(string) - } - if len(msg.Body) != 0 { - s += "\n" - } - for i, v := range msg.Body { - s += " " + MakeVariant(v).String() - if i != len(msg.Body)-1 { - s += "\n" - } - } - return s -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/object.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/object.go deleted file mode 100644 index 7ef45da4c88c606a4917dd97b8bfce28e821207d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/object.go +++ /dev/null @@ -1,126 +0,0 @@ -package dbus - -import ( - "errors" - "strings" -) - -// BusObject is the interface of a remote object on which methods can be -// invoked. -type BusObject interface { - Call(method string, flags Flags, args ...interface{}) *Call - Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call - GetProperty(p string) (Variant, error) - Destination() string - Path() ObjectPath -} - -// Object represents a remote object on which methods can be invoked. -type Object struct { - conn *Conn - dest string - path ObjectPath -} - -// Call calls a method with (*Object).Go and waits for its reply. -func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { - return <-o.Go(method, flags, make(chan *Call, 1), args...).Done -} - -// Go calls a method with the given arguments asynchronously. It returns a -// Call structure representing this method call. The passed channel will -// return the same value once the call is done. If ch is nil, a new channel -// will be allocated. Otherwise, ch has to be buffered or Go will panic. -// -// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure -// is returned of which only the Err member is valid. -// -// If the method parameter contains a dot ('.'), the part before the last dot -// specifies the interface on which the method is called. -func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { - iface := "" - i := strings.LastIndex(method, ".") - if i != -1 { - iface = method[:i] - } - method = method[i+1:] - msg := new(Message) - msg.Type = TypeMethodCall - msg.serial = o.conn.getSerial() - msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldPath] = MakeVariant(o.path) - msg.Headers[FieldDestination] = MakeVariant(o.dest) - msg.Headers[FieldMember] = MakeVariant(method) - if iface != "" { - msg.Headers[FieldInterface] = MakeVariant(iface) - } - msg.Body = args - if len(args) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) - } - if msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 10) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Object).Go") - } - call := &Call{ - Destination: o.dest, - Path: o.path, - Method: method, - Args: args, - Done: ch, - } - o.conn.callsLck.Lock() - o.conn.calls[msg.serial] = call - o.conn.callsLck.Unlock() - o.conn.outLck.RLock() - if o.conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - o.conn.out <- msg - } - o.conn.outLck.RUnlock() - return call - } - o.conn.outLck.RLock() - defer o.conn.outLck.RUnlock() - if o.conn.closed { - return &Call{Err: ErrClosed} - } - o.conn.out <- msg - return &Call{Err: nil} -} - -// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given -// object. The property name must be given in interface.member notation. -func (o *Object) GetProperty(p string) (Variant, error) { - idx := strings.LastIndex(p, ".") - if idx == -1 || idx+1 == len(p) { - return Variant{}, errors.New("dbus: invalid property " + p) - } - - iface := p[:idx] - prop := p[idx+1:] - - result := Variant{} - err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) - - if err != nil { - return Variant{}, err - } - - return result, nil -} - -// Destination returns the destination that calls on o are sent to. -func (o *Object) Destination() string { - return o.dest -} - -// Path returns the path that calls on o are sent to. -func (o *Object) Path() ObjectPath { - return o.path -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/prop/prop.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/prop/prop.go deleted file mode 100644 index 834a1fa89327220b9d4c57efc57bd8ccd682bc9e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/prop/prop.go +++ /dev/null @@ -1,264 +0,0 @@ -// Package prop provides the Properties struct which can be used to implement -// org.freedesktop.DBus.Properties. -package prop - -import ( - "github.com/godbus/dbus" - "github.com/godbus/dbus/introspect" - "sync" -) - -// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is -// emitted for a property. If it is EmitTrue, the signal is emitted. If it is -// EmitInvalidates, the signal is also emitted, but the new value of the property -// is not disclosed. -type EmitType byte - -const ( - EmitFalse EmitType = iota - EmitTrue - EmitInvalidates -) - -// ErrIfaceNotFound is the error returned to peers who try to access properties -// on interfaces that aren't found. -var ErrIfaceNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil) - -// ErrPropNotFound is the error returned to peers trying to access properties -// that aren't found. -var ErrPropNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil) - -// ErrReadOnly is the error returned to peers trying to set a read-only -// property. -var ErrReadOnly = dbus.NewError("org.freedesktop.DBus.Properties.Error.ReadOnly", nil) - -// ErrInvalidArg is returned to peers if the type of the property that is being -// changed and the argument don't match. -var ErrInvalidArg = dbus.NewError("org.freedesktop.DBus.Properties.Error.InvalidArg", nil) - -// The introspection data for the org.freedesktop.DBus.Properties interface. -var IntrospectData = introspect.Interface{ - Name: "org.freedesktop.DBus.Properties", - Methods: []introspect.Method{ - { - Name: "Get", - Args: []introspect.Arg{ - {"interface", "s", "in"}, - {"property", "s", "in"}, - {"value", "v", "out"}, - }, - }, - { - Name: "GetAll", - Args: []introspect.Arg{ - {"interface", "s", "in"}, - {"props", "a{sv}", "out"}, - }, - }, - { - Name: "Set", - Args: []introspect.Arg{ - {"interface", "s", "in"}, - {"property", "s", "in"}, - {"value", "v", "in"}, - }, - }, - }, - Signals: []introspect.Signal{ - { - Name: "PropertiesChanged", - Args: []introspect.Arg{ - {"interface", "s", "out"}, - {"changed_properties", "a{sv}", "out"}, - {"invalidates_properties", "as", "out"}, - }, - }, - }, -} - -// The introspection data for the org.freedesktop.DBus.Properties interface, as -// a string. -const IntrospectDataString = ` - <interface name="org.freedesktop.DBus.Introspectable"> - <method name="Get"> - <arg name="interface" direction="in" type="s"/> - <arg name="property" direction="in" type="s"/> - <arg name="value" direction="out" type="v"/> - </method> - <method name="GetAll"> - <arg name="interface" direction="in" type="s"/> - <arg name="props" direction="out" type="a{sv}"/> - </method> - <method name="Set"> - <arg name="interface" direction="in" type="s"/> - <arg name="property" direction="in" type="s"/> - <arg name="value" direction="in" type="v"/> - </method> - <signal name="PropertiesChanged"> - <arg name="interface" type="s"/> - <arg name="changed_properties" type="a{sv}"/> - <arg name="invalidates_properties" type="as"/> - </signal> - </interface> -` - -// Prop represents a single property. It is used for creating a Properties -// value. -type Prop struct { - // Initial value. Must be a DBus-representable type. - Value interface{} - - // If true, the value can be modified by calls to Set. - Writable bool - - // Controls how org.freedesktop.DBus.Properties.PropertiesChanged is - // emitted if this property changes. - Emit EmitType - - // If not nil, anytime this property is changed by Set, this function is - // called with an appropiate Change as its argument. If the returned error - // is not nil, it is sent back to the caller of Set and the property is not - // changed. - Callback func(*Change) *dbus.Error -} - -// Change represents a change of a property by a call to Set. -type Change struct { - Props *Properties - Iface string - Name string - Value interface{} -} - -// Properties is a set of values that can be made available to the message bus -// using the org.freedesktop.DBus.Properties interface. It is safe for -// concurrent use by multiple goroutines. -type Properties struct { - m map[string]map[string]*Prop - mut sync.RWMutex - conn *dbus.Conn - path dbus.ObjectPath -} - -// New returns a new Properties structure that manages the given properties. -// The key for the first-level map of props is the name of the interface; the -// second-level key is the name of the property. The returned structure will be -// exported as org.freedesktop.DBus.Properties on path. -func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties { - p := &Properties{m: props, conn: conn, path: path} - conn.Export(p, path, "org.freedesktop.DBus.Properties") - return p -} - -// Get implements org.freedesktop.DBus.Properties.Get. -func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) { - p.mut.RLock() - defer p.mut.RUnlock() - m, ok := p.m[iface] - if !ok { - return dbus.Variant{}, ErrIfaceNotFound - } - prop, ok := m[property] - if !ok { - return dbus.Variant{}, ErrPropNotFound - } - return dbus.MakeVariant(prop.Value), nil -} - -// GetAll implements org.freedesktop.DBus.Properties.GetAll. -func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) { - p.mut.RLock() - defer p.mut.RUnlock() - m, ok := p.m[iface] - if !ok { - return nil, ErrIfaceNotFound - } - rm := make(map[string]dbus.Variant, len(m)) - for k, v := range m { - rm[k] = dbus.MakeVariant(v.Value) - } - return rm, nil -} - -// GetMust returns the value of the given property and panics if either the -// interface or the property name are invalid. -func (p *Properties) GetMust(iface, property string) interface{} { - p.mut.RLock() - defer p.mut.RUnlock() - return p.m[iface][property].Value -} - -// Introspection returns the introspection data that represents the properties -// of iface. -func (p *Properties) Introspection(iface string) []introspect.Property { - p.mut.RLock() - defer p.mut.RUnlock() - m := p.m[iface] - s := make([]introspect.Property, 0, len(m)) - for k, v := range m { - p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()} - if v.Writable { - p.Access = "readwrite" - } else { - p.Access = "read" - } - s = append(s, p) - } - return s -} - -// set sets the given property and emits PropertyChanged if appropiate. p.mut -// must already be locked. -func (p *Properties) set(iface, property string, v interface{}) { - prop := p.m[iface][property] - prop.Value = v - switch prop.Emit { - case EmitFalse: - // do nothing - case EmitInvalidates: - p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged", - iface, map[string]dbus.Variant{}, []string{property}) - case EmitTrue: - p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged", - iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)}, - []string{}) - default: - panic("invalid value for EmitType") - } -} - -// Set implements org.freedesktop.Properties.Set. -func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error { - p.mut.Lock() - defer p.mut.Unlock() - m, ok := p.m[iface] - if !ok { - return ErrIfaceNotFound - } - prop, ok := m[property] - if !ok { - return ErrPropNotFound - } - if !prop.Writable { - return ErrReadOnly - } - if newv.Signature() != dbus.SignatureOf(prop.Value) { - return ErrInvalidArg - } - if prop.Callback != nil { - err := prop.Callback(&Change{p, iface, property, newv.Value()}) - if err != nil { - return err - } - } - p.set(iface, property, newv.Value()) - return nil -} - -// SetMust sets the value of the given property and panics if the interface or -// the property name are invalid. -func (p *Properties) SetMust(iface, property string, v interface{}) { - p.mut.Lock() - p.set(iface, property, v) - p.mut.Unlock() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/sig.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/sig.go deleted file mode 100644 index f45b53ce1b275fb9fe321bc230e6aa3b6273133f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/sig.go +++ /dev/null @@ -1,257 +0,0 @@ -package dbus - -import ( - "fmt" - "reflect" - "strings" -) - -var sigToType = map[byte]reflect.Type{ - 'y': byteType, - 'b': boolType, - 'n': int16Type, - 'q': uint16Type, - 'i': int32Type, - 'u': uint32Type, - 'x': int64Type, - 't': uint64Type, - 'd': float64Type, - 's': stringType, - 'g': signatureType, - 'o': objectPathType, - 'v': variantType, - 'h': unixFDIndexType, -} - -// Signature represents a correct type signature as specified by the D-Bus -// specification. The zero value represents the empty signature, "". -type Signature struct { - str string -} - -// SignatureOf returns the concatenation of all the signatures of the given -// values. It panics if one of them is not representable in D-Bus. -func SignatureOf(vs ...interface{}) Signature { - var s string - for _, v := range vs { - s += getSignature(reflect.TypeOf(v)) - } - return Signature{s} -} - -// SignatureOfType returns the signature of the given type. It panics if the -// type is not representable in D-Bus. -func SignatureOfType(t reflect.Type) Signature { - return Signature{getSignature(t)} -} - -// getSignature returns the signature of the given type and panics on unknown types. -func getSignature(t reflect.Type) string { - // handle simple types first - switch t.Kind() { - case reflect.Uint8: - return "y" - case reflect.Bool: - return "b" - case reflect.Int16: - return "n" - case reflect.Uint16: - return "q" - case reflect.Int32: - if t == unixFDType { - return "h" - } - return "i" - case reflect.Uint32: - if t == unixFDIndexType { - return "h" - } - return "u" - case reflect.Int64: - return "x" - case reflect.Uint64: - return "t" - case reflect.Float64: - return "d" - case reflect.Ptr: - return getSignature(t.Elem()) - case reflect.String: - if t == objectPathType { - return "o" - } - return "s" - case reflect.Struct: - if t == variantType { - return "v" - } else if t == signatureType { - return "g" - } - var s string - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - s += getSignature(t.Field(i).Type) - } - } - return "(" + s + ")" - case reflect.Array, reflect.Slice: - return "a" + getSignature(t.Elem()) - case reflect.Map: - if !isKeyType(t.Key()) { - panic(InvalidTypeError{t}) - } - return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" - } - panic(InvalidTypeError{t}) -} - -// ParseSignature returns the signature represented by this string, or a -// SignatureError if the string is not a valid signature. -func ParseSignature(s string) (sig Signature, err error) { - if len(s) == 0 { - return - } - if len(s) > 255 { - return Signature{""}, SignatureError{s, "too long"} - } - sig.str = s - for err == nil && len(s) != 0 { - err, s = validSingle(s, 0) - } - if err != nil { - sig = Signature{""} - } - - return -} - -// ParseSignatureMust behaves like ParseSignature, except that it panics if s -// is not valid. -func ParseSignatureMust(s string) Signature { - sig, err := ParseSignature(s) - if err != nil { - panic(err) - } - return sig -} - -// Empty retruns whether the signature is the empty signature. -func (s Signature) Empty() bool { - return s.str == "" -} - -// Single returns whether the signature represents a single, complete type. -func (s Signature) Single() bool { - err, r := validSingle(s.str, 0) - return err != nil && r == "" -} - -// String returns the signature's string representation. -func (s Signature) String() string { - return s.str -} - -// A SignatureError indicates that a signature passed to a function or received -// on a connection is not a valid signature. -type SignatureError struct { - Sig string - Reason string -} - -func (e SignatureError) Error() string { - return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason) -} - -// Try to read a single type from this string. If it was successfull, err is nil -// and rem is the remaining unparsed part. Otherwise, err is a non-nil -// SignatureError and rem is "". depth is the current recursion depth which may -// not be greater than 64 and should be given as 0 on the first call. -func validSingle(s string, depth int) (err error, rem string) { - if s == "" { - return SignatureError{Sig: s, Reason: "empty signature"}, "" - } - if depth > 64 { - return SignatureError{Sig: s, Reason: "container nesting too deep"}, "" - } - switch s[0] { - case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h': - return nil, s[1:] - case 'a': - if len(s) > 1 && s[1] == '{' { - i := findMatching(s[1:], '{', '}') - if i == -1 { - return SignatureError{Sig: s, Reason: "unmatched '{'"}, "" - } - i++ - rem = s[i+1:] - s = s[2:i] - if err, _ = validSingle(s[:1], depth+1); err != nil { - return err, "" - } - err, nr := validSingle(s[1:], depth+1) - if err != nil { - return err, "" - } - if nr != "" { - return SignatureError{Sig: s, Reason: "too many types in dict"}, "" - } - return nil, rem - } - return validSingle(s[1:], depth+1) - case '(': - i := findMatching(s, '(', ')') - if i == -1 { - return SignatureError{Sig: s, Reason: "unmatched ')'"}, "" - } - rem = s[i+1:] - s = s[1:i] - for err == nil && s != "" { - err, s = validSingle(s, depth+1) - } - if err != nil { - rem = "" - } - return - } - return SignatureError{Sig: s, Reason: "invalid type character"}, "" -} - -func findMatching(s string, left, right rune) int { - n := 0 - for i, v := range s { - if v == left { - n++ - } else if v == right { - n-- - } - if n == 0 { - return i - } - } - return -1 -} - -// typeFor returns the type of the given signature. It ignores any left over -// characters and panics if s doesn't start with a valid type signature. -func typeFor(s string) (t reflect.Type) { - err, _ := validSingle(s, 0) - if err != nil { - panic(err) - } - - if t, ok := sigToType[s[0]]; ok { - return t - } - switch s[0] { - case 'a': - if s[1] == '{' { - i := strings.LastIndex(s, "}") - t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i])) - } else { - t = reflect.SliceOf(typeFor(s[1:])) - } - case '(': - t = interfacesType - } - return -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_darwin.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_darwin.go deleted file mode 100644 index 1bba0d6bf781e7197d4de04a4812d19b74899186..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_darwin.go +++ /dev/null @@ -1,6 +0,0 @@ -package dbus - -func (t *unixTransport) SendNullByte() error { - _, err := t.Write([]byte{0}) - return err -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_generic.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_generic.go deleted file mode 100644 index 46f8f49d699b7a6819bcd78a231e78df6bf15b83..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_generic.go +++ /dev/null @@ -1,35 +0,0 @@ -package dbus - -import ( - "encoding/binary" - "errors" - "io" -) - -type genericTransport struct { - io.ReadWriteCloser -} - -func (t genericTransport) SendNullByte() error { - _, err := t.Write([]byte{0}) - return err -} - -func (t genericTransport) SupportsUnixFDs() bool { - return false -} - -func (t genericTransport) EnableUnixFDs() {} - -func (t genericTransport) ReadMessage() (*Message, error) { - return DecodeMessage(t) -} - -func (t genericTransport) SendMessage(msg *Message) error { - for _, v := range msg.Body { - if _, ok := v.(UnixFD); ok { - return errors.New("dbus: unix fd passing not enabled") - } - } - return msg.EncodeTo(t, binary.LittleEndian) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go deleted file mode 100644 index 3fafeabb15b75d12c874173fc62f7206b4a21a1d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go +++ /dev/null @@ -1,196 +0,0 @@ -//+build !windows - -package dbus - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "net" - "syscall" -) - -type oobReader struct { - conn *net.UnixConn - oob []byte - buf [4096]byte -} - -func (o *oobReader) Read(b []byte) (n int, err error) { - n, oobn, flags, _, err := o.conn.ReadMsgUnix(b, o.buf[:]) - if err != nil { - return n, err - } - if flags&syscall.MSG_CTRUNC != 0 { - return n, errors.New("dbus: control data truncated (too many fds received)") - } - o.oob = append(o.oob, o.buf[:oobn]...) - return n, nil -} - -type unixTransport struct { - *net.UnixConn - hasUnixFDs bool -} - -func newUnixTransport(keys string) (transport, error) { - var err error - - t := new(unixTransport) - abstract := getKey(keys, "abstract") - path := getKey(keys, "path") - switch { - case abstract == "" && path == "": - return nil, errors.New("dbus: invalid address (neither path nor abstract set)") - case abstract != "" && path == "": - t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: "@" + abstract, Net: "unix"}) - if err != nil { - return nil, err - } - return t, nil - case abstract == "" && path != "": - t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: path, Net: "unix"}) - if err != nil { - return nil, err - } - return t, nil - default: - return nil, errors.New("dbus: invalid address (both path and abstract set)") - } -} - -func init() { - transports["unix"] = newUnixTransport -} - -func (t *unixTransport) EnableUnixFDs() { - t.hasUnixFDs = true -} - -func (t *unixTransport) ReadMessage() (*Message, error) { - var ( - blen, hlen uint32 - csheader [16]byte - headers []header - order binary.ByteOrder - unixfds uint32 - ) - // To be sure that all bytes of out-of-band data are read, we use a special - // reader that uses ReadUnix on the underlying connection instead of Read - // and gathers the out-of-band data in a buffer. - rd := &oobReader{conn: t.UnixConn} - // read the first 16 bytes (the part of the header that has a constant size), - // from which we can figure out the length of the rest of the message - if _, err := io.ReadFull(rd, csheader[:]); err != nil { - return nil, err - } - switch csheader[0] { - case 'l': - order = binary.LittleEndian - case 'B': - order = binary.BigEndian - default: - return nil, InvalidMessageError("invalid byte order") - } - // csheader[4:8] -> length of message body, csheader[12:16] -> length of - // header fields (without alignment) - binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen) - binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen) - if hlen%8 != 0 { - hlen += 8 - (hlen % 8) - } - - // decode headers and look for unix fds - headerdata := make([]byte, hlen+4) - copy(headerdata, csheader[12:]) - if _, err := io.ReadFull(t, headerdata[4:]); err != nil { - return nil, err - } - dec := newDecoder(bytes.NewBuffer(headerdata), order) - dec.pos = 12 - vs, err := dec.Decode(Signature{"a(yv)"}) - if err != nil { - return nil, err - } - Store(vs, &headers) - for _, v := range headers { - if v.Field == byte(FieldUnixFDs) { - unixfds, _ = v.Variant.value.(uint32) - } - } - all := make([]byte, 16+hlen+blen) - copy(all, csheader[:]) - copy(all[16:], headerdata[4:]) - if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { - return nil, err - } - if unixfds != 0 { - if !t.hasUnixFDs { - return nil, errors.New("dbus: got unix fds on unsupported transport") - } - // read the fds from the OOB data - scms, err := syscall.ParseSocketControlMessage(rd.oob) - if err != nil { - return nil, err - } - if len(scms) != 1 { - return nil, errors.New("dbus: received more than one socket control message") - } - fds, err := syscall.ParseUnixRights(&scms[0]) - if err != nil { - return nil, err - } - msg, err := DecodeMessage(bytes.NewBuffer(all)) - if err != nil { - return nil, err - } - // substitute the values in the message body (which are indices for the - // array receiver via OOB) with the actual values - for i, v := range msg.Body { - if j, ok := v.(UnixFDIndex); ok { - if uint32(j) >= unixfds { - return nil, InvalidMessageError("invalid index for unix fd") - } - msg.Body[i] = UnixFD(fds[j]) - } - } - return msg, nil - } - return DecodeMessage(bytes.NewBuffer(all)) -} - -func (t *unixTransport) SendMessage(msg *Message) error { - fds := make([]int, 0) - for i, v := range msg.Body { - if fd, ok := v.(UnixFD); ok { - msg.Body[i] = UnixFDIndex(len(fds)) - fds = append(fds, int(fd)) - } - } - if len(fds) != 0 { - if !t.hasUnixFDs { - return errors.New("dbus: unix fd passing not enabled") - } - msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds))) - oob := syscall.UnixRights(fds...) - buf := new(bytes.Buffer) - msg.EncodeTo(buf, binary.LittleEndian) - n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil) - if err != nil { - return err - } - if n != buf.Len() || oobn != len(oob) { - return io.ErrShortWrite - } - } else { - if err := msg.EncodeTo(t, binary.LittleEndian); err != nil { - return nil - } - } - return nil -} - -func (t *unixTransport) SupportsUnixFDs() bool { - return true -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_dragonfly.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_dragonfly.go deleted file mode 100644 index a8cd39395f02dd613feba13aaf1fa0cb441d9922..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_dragonfly.go +++ /dev/null @@ -1,95 +0,0 @@ -// The UnixCredentials system call is currently only implemented on Linux -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// https://golang.org/s/go1.4-syscall -// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys - -// Local implementation of the UnixCredentials system call for DragonFly BSD - -package dbus - -/* -#include <sys/ucred.h> -*/ -import "C" - -import ( - "io" - "os" - "syscall" - "unsafe" -) - -// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go -// http://golang.org/src/pkg/syscall/ztypes_dragonfly_amd64.go -type Ucred struct { - Pid int32 - Uid uint32 - Gid uint32 -} - -// http://golang.org/src/pkg/syscall/types_linux.go -// http://golang.org/src/pkg/syscall/types_dragonfly.go -// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/ucred.h -const ( - SizeofUcred = C.sizeof_struct_ucred -) - -// http://golang.org/src/pkg/syscall/sockcmsg_unix.go -func cmsgAlignOf(salen int) int { - // From http://golang.org/src/pkg/syscall/sockcmsg_unix.go - //salign := sizeofPtr - // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels - // still require 32-bit aligned access to network subsystem. - //if darwin64Bit || dragonfly64Bit { - // salign = 4 - //} - salign := 4 - return (salen + salign - 1) & ^(salign - 1) -} - -// http://golang.org/src/pkg/syscall/sockcmsg_unix.go -func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer { - return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr))) -} - -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// UnixCredentials encodes credentials into a socket control message -// for sending to another process. This can be used for -// authentication. -func UnixCredentials(ucred *Ucred) []byte { - b := make([]byte, syscall.CmsgSpace(SizeofUcred)) - h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) - h.Level = syscall.SOL_SOCKET - h.Type = syscall.SCM_CREDS - h.SetLen(syscall.CmsgLen(SizeofUcred)) - *((*Ucred)(cmsgData(h))) = *ucred - return b -} - -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// ParseUnixCredentials decodes a socket control message that contains -// credentials in a Ucred structure. To receive such a message, the -// SO_PASSCRED option must be enabled on the socket. -func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) { - if m.Header.Level != syscall.SOL_SOCKET { - return nil, syscall.EINVAL - } - if m.Header.Type != syscall.SCM_CREDS { - return nil, syscall.EINVAL - } - ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) - return &ucred, nil -} - -func (t *unixTransport) SendNullByte() error { - ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} - b := UnixCredentials(ucred) - _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) - if err != nil { - return err - } - if oobn != len(b) { - return io.ErrShortWrite - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_linux.go deleted file mode 100644 index d9dfdf698210da415cbea49a0bd97adecdb4ee3b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/transport_unixcred_linux.go +++ /dev/null @@ -1,25 +0,0 @@ -// The UnixCredentials system call is currently only implemented on Linux -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// https://golang.org/s/go1.4-syscall -// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys - -package dbus - -import ( - "io" - "os" - "syscall" -) - -func (t *unixTransport) SendNullByte() error { - ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} - b := syscall.UnixCredentials(ucred) - _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) - if err != nil { - return err - } - if oobn != len(b) { - return io.ErrShortWrite - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant.go deleted file mode 100644 index b7b13ae90ddf1afe0ecfff584b3d632ef273e7d7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant.go +++ /dev/null @@ -1,139 +0,0 @@ -package dbus - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "strconv" -) - -// Variant represents the D-Bus variant type. -type Variant struct { - sig Signature - value interface{} -} - -// MakeVariant converts the given value to a Variant. It panics if v cannot be -// represented as a D-Bus type. -func MakeVariant(v interface{}) Variant { - return Variant{SignatureOf(v), v} -} - -// ParseVariant parses the given string as a variant as described at -// https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not -// empty, it is taken to be the expected signature for the variant. -func ParseVariant(s string, sig Signature) (Variant, error) { - tokens := varLex(s) - p := &varParser{tokens: tokens} - n, err := varMakeNode(p) - if err != nil { - return Variant{}, err - } - if sig.str == "" { - sig, err = varInfer(n) - if err != nil { - return Variant{}, err - } - } - v, err := n.Value(sig) - if err != nil { - return Variant{}, err - } - return MakeVariant(v), nil -} - -// format returns a formatted version of v and whether this string can be parsed -// unambigously. -func (v Variant) format() (string, bool) { - switch v.sig.str[0] { - case 'b', 'i': - return fmt.Sprint(v.value), true - case 'n', 'q', 'u', 'x', 't', 'd', 'h': - return fmt.Sprint(v.value), false - case 's': - return strconv.Quote(v.value.(string)), true - case 'o': - return strconv.Quote(string(v.value.(ObjectPath))), false - case 'g': - return strconv.Quote(v.value.(Signature).str), false - case 'v': - s, unamb := v.value.(Variant).format() - if !unamb { - return "<@" + v.value.(Variant).sig.str + " " + s + ">", true - } - return "<" + s + ">", true - case 'y': - return fmt.Sprintf("%#x", v.value.(byte)), false - } - rv := reflect.ValueOf(v.value) - switch rv.Kind() { - case reflect.Slice: - if rv.Len() == 0 { - return "[]", false - } - unamb := true - buf := bytes.NewBuffer([]byte("[")) - for i := 0; i < rv.Len(); i++ { - // TODO: slooow - s, b := MakeVariant(rv.Index(i).Interface()).format() - unamb = unamb && b - buf.WriteString(s) - if i != rv.Len()-1 { - buf.WriteString(", ") - } - } - buf.WriteByte(']') - return buf.String(), unamb - case reflect.Map: - if rv.Len() == 0 { - return "{}", false - } - unamb := true - var buf bytes.Buffer - kvs := make([]string, rv.Len()) - for i, k := range rv.MapKeys() { - s, b := MakeVariant(k.Interface()).format() - unamb = unamb && b - buf.Reset() - buf.WriteString(s) - buf.WriteString(": ") - s, b = MakeVariant(rv.MapIndex(k).Interface()).format() - unamb = unamb && b - buf.WriteString(s) - kvs[i] = buf.String() - } - buf.Reset() - buf.WriteByte('{') - sort.Strings(kvs) - for i, kv := range kvs { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(kv) - } - buf.WriteByte('}') - return buf.String(), unamb - } - return `"INVALID"`, true -} - -// Signature returns the D-Bus signature of the underlying value of v. -func (v Variant) Signature() Signature { - return v.sig -} - -// String returns the string representation of the underlying value of v as -// described at https://developer.gnome.org/glib/unstable/gvariant-text.html. -func (v Variant) String() string { - s, unamb := v.format() - if !unamb { - return "@" + v.sig.str + " " + s - } - return s -} - -// Value returns the underlying value of v. -func (v Variant) Value() interface{} { - return v.value -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_lexer.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_lexer.go deleted file mode 100644 index 332007d6f123204ae6e3c1a75cb6a2da4aed4928..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_lexer.go +++ /dev/null @@ -1,284 +0,0 @@ -package dbus - -import ( - "fmt" - "strings" - "unicode" - "unicode/utf8" -) - -// Heavily inspired by the lexer from text/template. - -type varToken struct { - typ varTokenType - val string -} - -type varTokenType byte - -const ( - tokEOF varTokenType = iota - tokError - tokNumber - tokString - tokBool - tokArrayStart - tokArrayEnd - tokDictStart - tokDictEnd - tokVariantStart - tokVariantEnd - tokComma - tokColon - tokType - tokByteString -) - -type varLexer struct { - input string - start int - pos int - width int - tokens []varToken -} - -type lexState func(*varLexer) lexState - -func varLex(s string) []varToken { - l := &varLexer{input: s} - l.run() - return l.tokens -} - -func (l *varLexer) accept(valid string) bool { - if strings.IndexRune(valid, l.next()) >= 0 { - return true - } - l.backup() - return false -} - -func (l *varLexer) backup() { - l.pos -= l.width -} - -func (l *varLexer) emit(t varTokenType) { - l.tokens = append(l.tokens, varToken{t, l.input[l.start:l.pos]}) - l.start = l.pos -} - -func (l *varLexer) errorf(format string, v ...interface{}) lexState { - l.tokens = append(l.tokens, varToken{ - tokError, - fmt.Sprintf(format, v...), - }) - return nil -} - -func (l *varLexer) ignore() { - l.start = l.pos -} - -func (l *varLexer) next() rune { - var r rune - - if l.pos >= len(l.input) { - l.width = 0 - return -1 - } - r, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) - l.pos += l.width - return r -} - -func (l *varLexer) run() { - for state := varLexNormal; state != nil; { - state = state(l) - } -} - -func (l *varLexer) peek() rune { - r := l.next() - l.backup() - return r -} - -func varLexNormal(l *varLexer) lexState { - for { - r := l.next() - switch { - case r == -1: - l.emit(tokEOF) - return nil - case r == '[': - l.emit(tokArrayStart) - case r == ']': - l.emit(tokArrayEnd) - case r == '{': - l.emit(tokDictStart) - case r == '}': - l.emit(tokDictEnd) - case r == '<': - l.emit(tokVariantStart) - case r == '>': - l.emit(tokVariantEnd) - case r == ':': - l.emit(tokColon) - case r == ',': - l.emit(tokComma) - case r == '\'' || r == '"': - l.backup() - return varLexString - case r == '@': - l.backup() - return varLexType - case unicode.IsSpace(r): - l.ignore() - case unicode.IsNumber(r) || r == '+' || r == '-': - l.backup() - return varLexNumber - case r == 'b': - pos := l.start - if n := l.peek(); n == '"' || n == '\'' { - return varLexByteString - } - // not a byte string; try to parse it as a type or bool below - l.pos = pos + 1 - l.width = 1 - fallthrough - default: - // either a bool or a type. Try bools first. - l.backup() - if l.pos+4 <= len(l.input) { - if l.input[l.pos:l.pos+4] == "true" { - l.pos += 4 - l.emit(tokBool) - continue - } - } - if l.pos+5 <= len(l.input) { - if l.input[l.pos:l.pos+5] == "false" { - l.pos += 5 - l.emit(tokBool) - continue - } - } - // must be a type. - return varLexType - } - } -} - -var varTypeMap = map[string]string{ - "boolean": "b", - "byte": "y", - "int16": "n", - "uint16": "q", - "int32": "i", - "uint32": "u", - "int64": "x", - "uint64": "t", - "double": "f", - "string": "s", - "objectpath": "o", - "signature": "g", -} - -func varLexByteString(l *varLexer) lexState { - q := l.next() -Loop: - for { - switch l.next() { - case '\\': - if r := l.next(); r != -1 { - break - } - fallthrough - case -1: - return l.errorf("unterminated bytestring") - case q: - break Loop - } - } - l.emit(tokByteString) - return varLexNormal -} - -func varLexNumber(l *varLexer) lexState { - l.accept("+-") - digits := "0123456789" - if l.accept("0") { - if l.accept("x") { - digits = "0123456789abcdefABCDEF" - } else { - digits = "01234567" - } - } - for strings.IndexRune(digits, l.next()) >= 0 { - } - l.backup() - if l.accept(".") { - for strings.IndexRune(digits, l.next()) >= 0 { - } - l.backup() - } - if l.accept("eE") { - l.accept("+-") - for strings.IndexRune("0123456789", l.next()) >= 0 { - } - l.backup() - } - if r := l.peek(); unicode.IsLetter(r) { - l.next() - return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) - } - l.emit(tokNumber) - return varLexNormal -} - -func varLexString(l *varLexer) lexState { - q := l.next() -Loop: - for { - switch l.next() { - case '\\': - if r := l.next(); r != -1 { - break - } - fallthrough - case -1: - return l.errorf("unterminated string") - case q: - break Loop - } - } - l.emit(tokString) - return varLexNormal -} - -func varLexType(l *varLexer) lexState { - at := l.accept("@") - for { - r := l.next() - if r == -1 { - break - } - if unicode.IsSpace(r) { - l.backup() - break - } - } - if at { - if _, err := ParseSignature(l.input[l.start+1 : l.pos]); err != nil { - return l.errorf("%s", err) - } - } else { - if _, ok := varTypeMap[l.input[l.start:l.pos]]; ok { - l.emit(tokType) - return varLexNormal - } - return l.errorf("unrecognized type %q", l.input[l.start:l.pos]) - } - l.emit(tokType) - return varLexNormal -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_parser.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_parser.go deleted file mode 100644 index d20f5da6dd22d7c2e31b7bfbafbb15bc6bf09901..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/godbus/dbus/variant_parser.go +++ /dev/null @@ -1,817 +0,0 @@ -package dbus - -import ( - "bytes" - "errors" - "fmt" - "io" - "reflect" - "strconv" - "strings" - "unicode/utf8" -) - -type varParser struct { - tokens []varToken - i int -} - -func (p *varParser) backup() { - p.i-- -} - -func (p *varParser) next() varToken { - if p.i < len(p.tokens) { - t := p.tokens[p.i] - p.i++ - return t - } - return varToken{typ: tokEOF} -} - -type varNode interface { - Infer() (Signature, error) - String() string - Sigs() sigSet - Value(Signature) (interface{}, error) -} - -func varMakeNode(p *varParser) (varNode, error) { - var sig Signature - - for { - t := p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - case tokNumber: - return varMakeNumNode(t, sig) - case tokString: - return varMakeStringNode(t, sig) - case tokBool: - if sig.str != "" && sig.str != "b" { - return nil, varTypeError{t.val, sig} - } - b, err := strconv.ParseBool(t.val) - if err != nil { - return nil, err - } - return boolNode(b), nil - case tokArrayStart: - return varMakeArrayNode(p, sig) - case tokVariantStart: - return varMakeVariantNode(p, sig) - case tokDictStart: - return varMakeDictNode(p, sig) - case tokType: - if sig.str != "" { - return nil, errors.New("unexpected type annotation") - } - if t.val[0] == '@' { - sig.str = t.val[1:] - } else { - sig.str = varTypeMap[t.val] - } - case tokByteString: - if sig.str != "" && sig.str != "ay" { - return nil, varTypeError{t.val, sig} - } - b, err := varParseByteString(t.val) - if err != nil { - return nil, err - } - return byteStringNode(b), nil - default: - return nil, fmt.Errorf("unexpected %q", t.val) - } - } -} - -type varTypeError struct { - val string - sig Signature -} - -func (e varTypeError) Error() string { - return fmt.Sprintf("dbus: can't parse %q as type %q", e.val, e.sig.str) -} - -type sigSet map[Signature]bool - -func (s sigSet) Empty() bool { - return len(s) == 0 -} - -func (s sigSet) Intersect(s2 sigSet) sigSet { - r := make(sigSet) - for k := range s { - if s2[k] { - r[k] = true - } - } - return r -} - -func (s sigSet) Single() (Signature, bool) { - if len(s) == 1 { - for k := range s { - return k, true - } - } - return Signature{}, false -} - -func (s sigSet) ToArray() sigSet { - r := make(sigSet, len(s)) - for k := range s { - r[Signature{"a" + k.str}] = true - } - return r -} - -type numNode struct { - sig Signature - str string - val interface{} -} - -var numSigSet = sigSet{ - Signature{"y"}: true, - Signature{"n"}: true, - Signature{"q"}: true, - Signature{"i"}: true, - Signature{"u"}: true, - Signature{"x"}: true, - Signature{"t"}: true, - Signature{"d"}: true, -} - -func (n numNode) Infer() (Signature, error) { - if strings.ContainsAny(n.str, ".e") { - return Signature{"d"}, nil - } - return Signature{"i"}, nil -} - -func (n numNode) String() string { - return n.str -} - -func (n numNode) Sigs() sigSet { - if n.sig.str != "" { - return sigSet{n.sig: true} - } - if strings.ContainsAny(n.str, ".e") { - return sigSet{Signature{"d"}: true} - } - return numSigSet -} - -func (n numNode) Value(sig Signature) (interface{}, error) { - if n.sig.str != "" && n.sig != sig { - return nil, varTypeError{n.str, sig} - } - if n.val != nil { - return n.val, nil - } - return varNumAs(n.str, sig) -} - -func varMakeNumNode(tok varToken, sig Signature) (varNode, error) { - if sig.str == "" { - return numNode{str: tok.val}, nil - } - num, err := varNumAs(tok.val, sig) - if err != nil { - return nil, err - } - return numNode{sig: sig, val: num}, nil -} - -func varNumAs(s string, sig Signature) (interface{}, error) { - isUnsigned := false - size := 32 - switch sig.str { - case "n": - size = 16 - case "i": - case "x": - size = 64 - case "y": - size = 8 - isUnsigned = true - case "q": - size = 16 - isUnsigned = true - case "u": - isUnsigned = true - case "t": - size = 64 - isUnsigned = true - case "d": - d, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, err - } - return d, nil - default: - return nil, varTypeError{s, sig} - } - base := 10 - if strings.HasPrefix(s, "0x") { - base = 16 - s = s[2:] - } - if strings.HasPrefix(s, "0") && len(s) != 1 { - base = 8 - s = s[1:] - } - if isUnsigned { - i, err := strconv.ParseUint(s, base, size) - if err != nil { - return nil, err - } - var v interface{} = i - switch sig.str { - case "y": - v = byte(i) - case "q": - v = uint16(i) - case "u": - v = uint32(i) - } - return v, nil - } - i, err := strconv.ParseInt(s, base, size) - if err != nil { - return nil, err - } - var v interface{} = i - switch sig.str { - case "n": - v = int16(i) - case "i": - v = int32(i) - } - return v, nil -} - -type stringNode struct { - sig Signature - str string // parsed - val interface{} // has correct type -} - -var stringSigSet = sigSet{ - Signature{"s"}: true, - Signature{"g"}: true, - Signature{"o"}: true, -} - -func (n stringNode) Infer() (Signature, error) { - return Signature{"s"}, nil -} - -func (n stringNode) String() string { - return n.str -} - -func (n stringNode) Sigs() sigSet { - if n.sig.str != "" { - return sigSet{n.sig: true} - } - return stringSigSet -} - -func (n stringNode) Value(sig Signature) (interface{}, error) { - if n.sig.str != "" && n.sig != sig { - return nil, varTypeError{n.str, sig} - } - if n.val != nil { - return n.val, nil - } - switch { - case sig.str == "g": - return Signature{n.str}, nil - case sig.str == "o": - return ObjectPath(n.str), nil - case sig.str == "s": - return n.str, nil - default: - return nil, varTypeError{n.str, sig} - } -} - -func varMakeStringNode(tok varToken, sig Signature) (varNode, error) { - if sig.str != "" && sig.str != "s" && sig.str != "g" && sig.str != "o" { - return nil, fmt.Errorf("invalid type %q for string", sig.str) - } - s, err := varParseString(tok.val) - if err != nil { - return nil, err - } - n := stringNode{str: s} - if sig.str == "" { - return stringNode{str: s}, nil - } - n.sig = sig - switch sig.str { - case "o": - n.val = ObjectPath(s) - case "g": - n.val = Signature{s} - case "s": - n.val = s - } - return n, nil -} - -func varParseString(s string) (string, error) { - // quotes are guaranteed to be there - s = s[1 : len(s)-1] - buf := new(bytes.Buffer) - for len(s) != 0 { - r, size := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && size == 1 { - return "", errors.New("invalid UTF-8") - } - s = s[size:] - if r != '\\' { - buf.WriteRune(r) - continue - } - r, size = utf8.DecodeRuneInString(s) - if r == utf8.RuneError && size == 1 { - return "", errors.New("invalid UTF-8") - } - s = s[size:] - switch r { - case 'a': - buf.WriteRune(0x7) - case 'b': - buf.WriteRune(0x8) - case 'f': - buf.WriteRune(0xc) - case 'n': - buf.WriteRune('\n') - case 'r': - buf.WriteRune('\r') - case 't': - buf.WriteRune('\t') - case '\n': - case 'u': - if len(s) < 4 { - return "", errors.New("short unicode escape") - } - r, err := strconv.ParseUint(s[:4], 16, 32) - if err != nil { - return "", err - } - buf.WriteRune(rune(r)) - s = s[4:] - case 'U': - if len(s) < 8 { - return "", errors.New("short unicode escape") - } - r, err := strconv.ParseUint(s[:8], 16, 32) - if err != nil { - return "", err - } - buf.WriteRune(rune(r)) - s = s[8:] - default: - buf.WriteRune(r) - } - } - return buf.String(), nil -} - -var boolSigSet = sigSet{Signature{"b"}: true} - -type boolNode bool - -func (boolNode) Infer() (Signature, error) { - return Signature{"b"}, nil -} - -func (b boolNode) String() string { - if b { - return "true" - } - return "false" -} - -func (boolNode) Sigs() sigSet { - return boolSigSet -} - -func (b boolNode) Value(sig Signature) (interface{}, error) { - if sig.str != "b" { - return nil, varTypeError{b.String(), sig} - } - return bool(b), nil -} - -type arrayNode struct { - set sigSet - children []varNode - val interface{} -} - -func (n arrayNode) Infer() (Signature, error) { - for _, v := range n.children { - csig, err := varInfer(v) - if err != nil { - continue - } - return Signature{"a" + csig.str}, nil - } - return Signature{}, fmt.Errorf("can't infer type for %q", n.String()) -} - -func (n arrayNode) String() string { - s := "[" - for i, v := range n.children { - s += v.String() - if i != len(n.children)-1 { - s += ", " - } - } - return s + "]" -} - -func (n arrayNode) Sigs() sigSet { - return n.set -} - -func (n arrayNode) Value(sig Signature) (interface{}, error) { - if n.set.Empty() { - // no type information whatsoever, so this must be an empty slice - return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil - } - if !n.set[sig] { - return nil, varTypeError{n.String(), sig} - } - s := reflect.MakeSlice(typeFor(sig.str), len(n.children), len(n.children)) - for i, v := range n.children { - rv, err := v.Value(Signature{sig.str[1:]}) - if err != nil { - return nil, err - } - s.Index(i).Set(reflect.ValueOf(rv)) - } - return s.Interface(), nil -} - -func varMakeArrayNode(p *varParser, sig Signature) (varNode, error) { - var n arrayNode - if sig.str != "" { - n.set = sigSet{sig: true} - } - if t := p.next(); t.typ == tokArrayEnd { - return n, nil - } else { - p.backup() - } -Loop: - for { - t := p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - } - p.backup() - cn, err := varMakeNode(p) - if err != nil { - return nil, err - } - if cset := cn.Sigs(); !cset.Empty() { - if n.set.Empty() { - n.set = cset.ToArray() - } else { - nset := cset.ToArray().Intersect(n.set) - if nset.Empty() { - return nil, fmt.Errorf("can't parse %q with given type information", cn.String()) - } - n.set = nset - } - } - n.children = append(n.children, cn) - switch t := p.next(); t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - case tokArrayEnd: - break Loop - case tokComma: - continue - default: - return nil, fmt.Errorf("unexpected %q", t.val) - } - } - return n, nil -} - -type variantNode struct { - n varNode -} - -var variantSet = sigSet{ - Signature{"v"}: true, -} - -func (variantNode) Infer() (Signature, error) { - return Signature{"v"}, nil -} - -func (n variantNode) String() string { - return "<" + n.n.String() + ">" -} - -func (variantNode) Sigs() sigSet { - return variantSet -} - -func (n variantNode) Value(sig Signature) (interface{}, error) { - if sig.str != "v" { - return nil, varTypeError{n.String(), sig} - } - sig, err := varInfer(n.n) - if err != nil { - return nil, err - } - v, err := n.n.Value(sig) - if err != nil { - return nil, err - } - return MakeVariant(v), nil -} - -func varMakeVariantNode(p *varParser, sig Signature) (varNode, error) { - n, err := varMakeNode(p) - if err != nil { - return nil, err - } - if t := p.next(); t.typ != tokVariantEnd { - return nil, fmt.Errorf("unexpected %q", t.val) - } - vn := variantNode{n} - if sig.str != "" && sig.str != "v" { - return nil, varTypeError{vn.String(), sig} - } - return variantNode{n}, nil -} - -type dictEntry struct { - key, val varNode -} - -type dictNode struct { - kset, vset sigSet - children []dictEntry - val interface{} -} - -func (n dictNode) Infer() (Signature, error) { - for _, v := range n.children { - ksig, err := varInfer(v.key) - if err != nil { - continue - } - vsig, err := varInfer(v.val) - if err != nil { - continue - } - return Signature{"a{" + ksig.str + vsig.str + "}"}, nil - } - return Signature{}, fmt.Errorf("can't infer type for %q", n.String()) -} - -func (n dictNode) String() string { - s := "{" - for i, v := range n.children { - s += v.key.String() + ": " + v.val.String() - if i != len(n.children)-1 { - s += ", " - } - } - return s + "}" -} - -func (n dictNode) Sigs() sigSet { - r := sigSet{} - for k := range n.kset { - for v := range n.vset { - sig := "a{" + k.str + v.str + "}" - r[Signature{sig}] = true - } - } - return r -} - -func (n dictNode) Value(sig Signature) (interface{}, error) { - set := n.Sigs() - if set.Empty() { - // no type information -> empty dict - return reflect.MakeMap(typeFor(sig.str)).Interface(), nil - } - if !set[sig] { - return nil, varTypeError{n.String(), sig} - } - m := reflect.MakeMap(typeFor(sig.str)) - ksig := Signature{sig.str[2:3]} - vsig := Signature{sig.str[3 : len(sig.str)-1]} - for _, v := range n.children { - kv, err := v.key.Value(ksig) - if err != nil { - return nil, err - } - vv, err := v.val.Value(vsig) - if err != nil { - return nil, err - } - m.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) - } - return m.Interface(), nil -} - -func varMakeDictNode(p *varParser, sig Signature) (varNode, error) { - var n dictNode - - if sig.str != "" { - if len(sig.str) < 5 { - return nil, fmt.Errorf("invalid signature %q for dict type", sig) - } - ksig := Signature{string(sig.str[2])} - vsig := Signature{sig.str[3 : len(sig.str)-1]} - n.kset = sigSet{ksig: true} - n.vset = sigSet{vsig: true} - } - if t := p.next(); t.typ == tokDictEnd { - return n, nil - } else { - p.backup() - } -Loop: - for { - t := p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - } - p.backup() - kn, err := varMakeNode(p) - if err != nil { - return nil, err - } - if kset := kn.Sigs(); !kset.Empty() { - if n.kset.Empty() { - n.kset = kset - } else { - n.kset = kset.Intersect(n.kset) - if n.kset.Empty() { - return nil, fmt.Errorf("can't parse %q with given type information", kn.String()) - } - } - } - t = p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - case tokColon: - default: - return nil, fmt.Errorf("unexpected %q", t.val) - } - t = p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - } - p.backup() - vn, err := varMakeNode(p) - if err != nil { - return nil, err - } - if vset := vn.Sigs(); !vset.Empty() { - if n.vset.Empty() { - n.vset = vset - } else { - n.vset = n.vset.Intersect(vset) - if n.vset.Empty() { - return nil, fmt.Errorf("can't parse %q with given type information", vn.String()) - } - } - } - n.children = append(n.children, dictEntry{kn, vn}) - t = p.next() - switch t.typ { - case tokEOF: - return nil, io.ErrUnexpectedEOF - case tokError: - return nil, errors.New(t.val) - case tokDictEnd: - break Loop - case tokComma: - continue - default: - return nil, fmt.Errorf("unexpected %q", t.val) - } - } - return n, nil -} - -type byteStringNode []byte - -var byteStringSet = sigSet{ - Signature{"ay"}: true, -} - -func (byteStringNode) Infer() (Signature, error) { - return Signature{"ay"}, nil -} - -func (b byteStringNode) String() string { - return string(b) -} - -func (b byteStringNode) Sigs() sigSet { - return byteStringSet -} - -func (b byteStringNode) Value(sig Signature) (interface{}, error) { - if sig.str != "ay" { - return nil, varTypeError{b.String(), sig} - } - return []byte(b), nil -} - -func varParseByteString(s string) ([]byte, error) { - // quotes and b at start are guaranteed to be there - b := make([]byte, 0, 1) - s = s[2 : len(s)-1] - for len(s) != 0 { - c := s[0] - s = s[1:] - if c != '\\' { - b = append(b, c) - continue - } - c = s[0] - s = s[1:] - switch c { - case 'a': - b = append(b, 0x7) - case 'b': - b = append(b, 0x8) - case 'f': - b = append(b, 0xc) - case 'n': - b = append(b, '\n') - case 'r': - b = append(b, '\r') - case 't': - b = append(b, '\t') - case 'x': - if len(s) < 2 { - return nil, errors.New("short escape") - } - n, err := strconv.ParseUint(s[:2], 16, 8) - if err != nil { - return nil, err - } - b = append(b, byte(n)) - s = s[2:] - case '0': - if len(s) < 3 { - return nil, errors.New("short escape") - } - n, err := strconv.ParseUint(s[:3], 8, 8) - if err != nil { - return nil, err - } - b = append(b, byte(n)) - s = s[3:] - default: - b = append(b, c) - } - } - return append(b, 0), nil -} - -func varInfer(n varNode) (Signature, error) { - if sig, ok := n.Sigs().Single(); ok { - return sig, nil - } - return n.Infer() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/LICENSE deleted file mode 100644 index 1b1b1921efa6dded19f74b196f76a96bf39c83dc..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/LICENSE +++ /dev/null @@ -1,31 +0,0 @@ -Go support for Protocol Buffers - Google's data interchange format - -Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go deleted file mode 100644 index 6c6a7d95f2c02eb9663e9d37df28208cfd5343df..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/clone.go +++ /dev/null @@ -1,197 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer deep copy and merge. -// TODO: MessageSet and RawMessage. - -package proto - -import ( - "log" - "reflect" - "strings" -) - -// Clone returns a deep copy of a protocol buffer. -func Clone(pb Message) Message { - in := reflect.ValueOf(pb) - if in.IsNil() { - return pb - } - - out := reflect.New(in.Type().Elem()) - // out is empty so a merge is a deep copy. - mergeStruct(out.Elem(), in.Elem()) - return out.Interface().(Message) -} - -// Merge merges src into dst. -// Required and optional fields that are set in src will be set to that value in dst. -// Elements of repeated fields will be appended. -// Merge panics if src and dst are not the same type, or if dst is nil. -func Merge(dst, src Message) { - in := reflect.ValueOf(src) - out := reflect.ValueOf(dst) - if out.IsNil() { - panic("proto: nil destination") - } - if in.Type() != out.Type() { - // Explicit test prior to mergeStruct so that mistyped nils will fail - panic("proto: type mismatch") - } - if in.IsNil() { - // Merging nil into non-nil is a quiet no-op - return - } - mergeStruct(out.Elem(), in.Elem()) -} - -func mergeStruct(out, in reflect.Value) { - for i := 0; i < in.NumField(); i++ { - f := in.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - mergeAny(out.Field(i), in.Field(i)) - } - - if emIn, ok := in.Addr().Interface().(extendableProto); ok { - emOut := out.Addr().Interface().(extendableProto) - mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap()) - } - - uf := in.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return - } - uin := uf.Bytes() - if len(uin) > 0 { - out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) - } -} - -func mergeAny(out, in reflect.Value) { - if in.Type() == protoMessageType { - if !in.IsNil() { - if out.IsNil() { - out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) - } else { - Merge(out.Interface().(Message), in.Interface().(Message)) - } - } - return - } - switch in.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - out.Set(in) - case reflect.Map: - if in.Len() == 0 { - return - } - if out.IsNil() { - out.Set(reflect.MakeMap(in.Type())) - } - // For maps with value types of *T or []byte we need to deep copy each value. - elemKind := in.Type().Elem().Kind() - for _, key := range in.MapKeys() { - var val reflect.Value - switch elemKind { - case reflect.Ptr: - val = reflect.New(in.Type().Elem().Elem()) - mergeAny(val, in.MapIndex(key)) - case reflect.Slice: - val = in.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - default: - val = in.MapIndex(key) - } - out.SetMapIndex(key, val) - } - case reflect.Ptr: - if in.IsNil() { - return - } - if out.IsNil() { - out.Set(reflect.New(in.Elem().Type())) - } - mergeAny(out.Elem(), in.Elem()) - case reflect.Slice: - if in.IsNil() { - return - } - if in.Type().Elem().Kind() == reflect.Uint8 { - // []byte is a scalar bytes field, not a repeated field. - // Make a deep copy. - // Append to []byte{} instead of []byte(nil) so that we never end up - // with a nil result. - out.SetBytes(append([]byte{}, in.Bytes()...)) - return - } - n := in.Len() - if out.IsNil() { - out.Set(reflect.MakeSlice(in.Type(), 0, n)) - } - switch in.Type().Elem().Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - out.Set(reflect.AppendSlice(out, in)) - default: - for i := 0; i < n; i++ { - x := reflect.Indirect(reflect.New(in.Type().Elem())) - mergeAny(x, in.Index(i)) - out.Set(reflect.Append(out, x)) - } - } - case reflect.Struct: - mergeStruct(out, in) - default: - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to copy %v", in) - } -} - -func mergeExtension(out, in map[int32]Extension) { - for extNum, eIn := range in { - eOut := Extension{desc: eIn.desc} - if eIn.value != nil { - v := reflect.New(reflect.TypeOf(eIn.value)).Elem() - mergeAny(v, reflect.ValueOf(eIn.value)) - eOut.value = v.Interface() - } - if eIn.enc != nil { - eOut.enc = make([]byte, len(eIn.enc)) - copy(eOut.enc, eIn.enc) - } - - out[extNum] = eOut - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go deleted file mode 100644 index 129792ed124501006be9fcc621cb6163a4613783..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/decode.go +++ /dev/null @@ -1,821 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for decoding protocol buffer data to construct in-memory representations. - */ - -import ( - "errors" - "fmt" - "io" - "os" - "reflect" -) - -// errOverflow is returned when an integer is too large to be represented. -var errOverflow = errors.New("proto: integer overflow") - -// The fundamental decoders that interpret bytes on the wire. -// Those that take integer types all return uint64 and are -// therefore of type valueDecoder. - -// DecodeVarint reads a varint-encoded integer from the slice. -// It returns the integer and the number of bytes consumed, or -// zero if there is not enough. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func DecodeVarint(buf []byte) (x uint64, n int) { - // x, n already 0 - for shift := uint(0); shift < 64; shift += 7 { - if n >= len(buf) { - return 0, 0 - } - b := uint64(buf[n]) - n++ - x |= (b & 0x7F) << shift - if (b & 0x80) == 0 { - return x, n - } - } - - // The number is too large to represent in a 64-bit value. - return 0, 0 -} - -// DecodeVarint reads a varint-encoded integer from the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) DecodeVarint() (x uint64, err error) { - // x, err already 0 - - i := p.index - l := len(p.buf) - - for shift := uint(0); shift < 64; shift += 7 { - if i >= l { - err = io.ErrUnexpectedEOF - return - } - b := p.buf[i] - i++ - x |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - p.index = i - return - } - } - - // The number is too large to represent in a 64-bit value. - err = errOverflow - return -} - -// DecodeFixed64 reads a 64-bit integer from the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) DecodeFixed64() (x uint64, err error) { - // x, err already 0 - i := p.index + 8 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-8]) - x |= uint64(p.buf[i-7]) << 8 - x |= uint64(p.buf[i-6]) << 16 - x |= uint64(p.buf[i-5]) << 24 - x |= uint64(p.buf[i-4]) << 32 - x |= uint64(p.buf[i-3]) << 40 - x |= uint64(p.buf[i-2]) << 48 - x |= uint64(p.buf[i-1]) << 56 - return -} - -// DecodeFixed32 reads a 32-bit integer from the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) DecodeFixed32() (x uint64, err error) { - // x, err already 0 - i := p.index + 4 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-4]) - x |= uint64(p.buf[i-3]) << 8 - x |= uint64(p.buf[i-2]) << 16 - x |= uint64(p.buf[i-1]) << 24 - return -} - -// DecodeZigzag64 reads a zigzag-encoded 64-bit integer -// from the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) DecodeZigzag64() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) - return -} - -// DecodeZigzag32 reads a zigzag-encoded 32-bit integer -// from the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) DecodeZigzag32() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) - return -} - -// These are not ValueDecoders: they produce an array of bytes or a string. -// bytes, embedded messages - -// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { - n, err := p.DecodeVarint() - if err != nil { - return nil, err - } - - nb := int(n) - if nb < 0 { - return nil, fmt.Errorf("proto: bad byte length %d", nb) - } - end := p.index + nb - if end < p.index || end > len(p.buf) { - return nil, io.ErrUnexpectedEOF - } - - if !alloc { - // todo: check if can get more uses of alloc=false - buf = p.buf[p.index:end] - p.index += nb - return - } - - buf = make([]byte, nb) - copy(buf, p.buf[p.index:]) - p.index += nb - return -} - -// DecodeStringBytes reads an encoded string from the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) DecodeStringBytes() (s string, err error) { - buf, err := p.DecodeRawBytes(false) - if err != nil { - return - } - return string(buf), nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -// If the protocol buffer has extensions, and the field matches, add it as an extension. -// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. -func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { - oi := o.index - - err := o.skip(t, tag, wire) - if err != nil { - return err - } - - if !unrecField.IsValid() { - return nil - } - - ptr := structPointer_Bytes(base, unrecField) - - // Add the skipped field to struct field - obuf := o.buf - - o.buf = *ptr - o.EncodeVarint(uint64(tag<<3 | wire)) - *ptr = append(o.buf, obuf[oi:o.index]...) - - o.buf = obuf - - return nil -} - -// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. -func (o *Buffer) skip(t reflect.Type, tag, wire int) error { - - var u uint64 - var err error - - switch wire { - case WireVarint: - _, err = o.DecodeVarint() - case WireFixed64: - _, err = o.DecodeFixed64() - case WireBytes: - _, err = o.DecodeRawBytes(false) - case WireFixed32: - _, err = o.DecodeFixed32() - case WireStartGroup: - for { - u, err = o.DecodeVarint() - if err != nil { - break - } - fwire := int(u & 0x7) - if fwire == WireEndGroup { - break - } - ftag := int(u >> 3) - err = o.skip(t, ftag, fwire) - if err != nil { - break - } - } - default: - err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) - } - return err -} - -// Unmarshaler is the interface representing objects that can -// unmarshal themselves. The method should reset the receiver before -// decoding starts. The argument points to data that may be -// overwritten, so implementations should not keep references to the -// buffer. -type Unmarshaler interface { - Unmarshal([]byte) error -} - -// Unmarshal parses the protocol buffer representation in buf and places the -// decoded result in pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// Unmarshal resets pb before starting to unmarshal, so any -// existing data in pb is always removed. Use UnmarshalMerge -// to preserve and append to existing data. -func Unmarshal(buf []byte, pb Message) error { - pb.Reset() - return UnmarshalMerge(buf, pb) -} - -// UnmarshalMerge parses the protocol buffer representation in buf and -// writes the decoded result to pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// UnmarshalMerge merges into existing data in pb. -// Most code should use Unmarshal instead. -func UnmarshalMerge(buf []byte, pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(Unmarshaler); ok { - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// Unmarshal parses the protocol buffer representation in the -// Buffer and places the decoded result in pb. If the struct -// underlying pb does not match the data in the buffer, the results can be -// unpredictable. -func (p *Buffer) Unmarshal(pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(Unmarshaler); ok { - err := u.Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - - typ, base, err := getbase(pb) - if err != nil { - return err - } - - err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) - - if collectStats { - stats.Decode++ - } - - return err -} - -// unmarshalType does the work of unmarshaling a structure. -func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { - var state errorState - required, reqFields := prop.reqCount, uint64(0) - - var err error - for err == nil && o.index < len(o.buf) { - oi := o.index - var u uint64 - u, err = o.DecodeVarint() - if err != nil { - break - } - wire := int(u & 0x7) - if wire == WireEndGroup { - if is_group { - return nil // input is satisfied - } - return fmt.Errorf("proto: %s: wiretype end group for non-group", st) - } - tag := int(u >> 3) - if tag <= 0 { - return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) - } - fieldnum, ok := prop.decoderTags.get(tag) - if !ok { - // Maybe it's an extension? - if prop.extendable { - if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) { - if err = o.skip(st, tag, wire); err == nil { - ext := e.ExtensionMap()[int32(tag)] // may be missing - ext.enc = append(ext.enc, o.buf[oi:o.index]...) - e.ExtensionMap()[int32(tag)] = ext - } - continue - } - } - err = o.skipAndSave(st, tag, wire, base, prop.unrecField) - continue - } - p := prop.Prop[fieldnum] - - if p.dec == nil { - fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) - continue - } - dec := p.dec - if wire != WireStartGroup && wire != p.WireType { - if wire == WireBytes && p.packedDec != nil { - // a packable field - dec = p.packedDec - } else { - err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) - continue - } - } - decErr := dec(o, p, base) - if decErr != nil && !state.shouldContinue(decErr, p) { - err = decErr - } - if err == nil && p.Required { - // Successfully decoded a required field. - if tag <= 64 { - // use bitmap for fields 1-64 to catch field reuse. - var mask uint64 = 1 << uint64(tag-1) - if reqFields&mask == 0 { - // new required field - reqFields |= mask - required-- - } - } else { - // This is imprecise. It can be fooled by a required field - // with a tag > 64 that is encoded twice; that's very rare. - // A fully correct implementation would require allocating - // a data structure, which we would like to avoid. - required-- - } - } - } - if err == nil { - if is_group { - return io.ErrUnexpectedEOF - } - if state.err != nil { - return state.err - } - if required > 0 { - // Not enough information to determine the exact field. If we use extra - // CPU, we could determine the field only if the missing required field - // has a tag <= 64 and we check reqFields. - return &RequiredNotSetError{"{Unknown}"} - } - } - return err -} - -// Individual type decoders -// For each, -// u is the decoded value, -// v is a pointer to the field (pointer) in the struct - -// Sizes of the pools to allocate inside the Buffer. -// The goal is modest amortization and allocation -// on at least 16-byte boundaries. -const ( - boolPoolSize = 16 - uint32PoolSize = 8 - uint64PoolSize = 4 -) - -// Decode a bool. -func (o *Buffer) dec_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - if len(o.bools) == 0 { - o.bools = make([]bool, boolPoolSize) - } - o.bools[0] = u != 0 - *structPointer_Bool(base, p.field) = &o.bools[0] - o.bools = o.bools[1:] - return nil -} - -func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - *structPointer_BoolVal(base, p.field) = u != 0 - return nil -} - -// Decode an int32. -func (o *Buffer) dec_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) - return nil -} - -func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) - return nil -} - -// Decode an int64. -func (o *Buffer) dec_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64_Set(structPointer_Word64(base, p.field), o, u) - return nil -} - -func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - word64Val_Set(structPointer_Word64Val(base, p.field), o, u) - return nil -} - -// Decode a string. -func (o *Buffer) dec_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_String(base, p.field) = &s - return nil -} - -func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - *structPointer_StringVal(base, p.field) = s - return nil -} - -// Decode a slice of bytes ([]byte). -func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - *structPointer_Bytes(base, p.field) = b - return nil -} - -// Decode a slice of bools ([]bool). -func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - v := structPointer_BoolSlice(base, p.field) - *v = append(*v, u != 0) - return nil -} - -// Decode a slice of bools ([]bool) in packed format. -func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { - v := structPointer_BoolSlice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded bools - - y := *v - for i := 0; i < nb; i++ { - u, err := p.valDec(o) - if err != nil { - return err - } - y = append(y, u != 0) - } - - *v = y - return nil -} - -// Decode a slice of int32s ([]int32). -func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - structPointer_Word32Slice(base, p.field).Append(uint32(u)) - return nil -} - -// Decode a slice of int32s ([]int32) in packed format. -func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int32s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(uint32(u)) - } - return nil -} - -// Decode a slice of int64s ([]int64). -func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { - u, err := p.valDec(o) - if err != nil { - return err - } - - structPointer_Word64Slice(base, p.field).Append(u) - return nil -} - -// Decode a slice of int64s ([]int64) in packed format. -func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Slice(base, p.field) - - nn, err := o.DecodeVarint() - if err != nil { - return err - } - nb := int(nn) // number of bytes of encoded int64s - - fin := o.index + nb - if fin < o.index { - return errOverflow - } - for o.index < fin { - u, err := p.valDec(o) - if err != nil { - return err - } - v.Append(u) - } - return nil -} - -// Decode a slice of strings ([]string). -func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { - s, err := o.DecodeStringBytes() - if err != nil { - return err - } - v := structPointer_StringSlice(base, p.field) - *v = append(*v, s) - return nil -} - -// Decode a slice of slice of bytes ([][]byte). -func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { - b, err := o.DecodeRawBytes(true) - if err != nil { - return err - } - v := structPointer_BytesSlice(base, p.field) - *v = append(*v, b) - return nil -} - -// Decode a map field. -func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - oi := o.index // index at the end of this map entry - o.index -= len(raw) // move buffer back to start of map entry - - mptr := structPointer_Map(base, p.field, p.mtype) // *map[K]V - if mptr.Elem().IsNil() { - mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) - } - v := mptr.Elem() // map[K]V - - // Prepare addressable doubly-indirect placeholders for the key and value types. - // See enc_new_map for why. - keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K - keybase := toStructPointer(keyptr.Addr()) // **K - - var valbase structPointer - var valptr reflect.Value - switch p.mtype.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valptr = reflect.ValueOf(&dummy) // *[]byte - valbase = toStructPointer(valptr) // *[]byte - case reflect.Ptr: - // message; valptr is **Msg; need to allocate the intermediate pointer - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valptr.Set(reflect.New(valptr.Type().Elem())) - valbase = toStructPointer(valptr) - default: - // everything else - valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V - valbase = toStructPointer(valptr.Addr()) // **V - } - - // Decode. - // This parses a restricted wire format, namely the encoding of a message - // with two fields. See enc_new_map for the format. - for o.index < oi { - // tagcode for key and value properties are always a single byte - // because they have tags 1 and 2. - tagcode := o.buf[o.index] - o.index++ - switch tagcode { - case p.mkeyprop.tagcode[0]: - if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { - return err - } - case p.mvalprop.tagcode[0]: - if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { - return err - } - default: - // TODO: Should we silently skip this instead? - return fmt.Errorf("proto: bad map data tag %d", raw[0]) - } - } - - v.SetMapIndex(keyptr.Elem(), valptr.Elem()) - return nil -} - -// Decode a group. -func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - return o.unmarshalType(p.stype, p.sprop, true, bas) -} - -// Decode an embedded message. -func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { - raw, e := o.DecodeRawBytes(false) - if e != nil { - return e - } - - bas := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(bas) { - // allocate new nested message - bas = toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := structPointer_Interface(bas, p.stype) - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, false, bas) - o.buf = obuf - o.index = oi - - return err -} - -// Decode a slice of embedded messages. -func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, false, base) -} - -// Decode a slice of embedded groups. -func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { - return o.dec_slice_struct(p, true, base) -} - -// Decode a slice of structs ([]*struct). -func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { - v := reflect.New(p.stype) - bas := toStructPointer(v) - structPointer_StructPointerSlice(base, p.field).Append(bas) - - if is_group { - err := o.unmarshalType(p.stype, p.sprop, is_group, bas) - return err - } - - raw, err := o.DecodeRawBytes(false) - if err != nil { - return err - } - - // If the object can unmarshal itself, let it. - if p.isUnmarshaler { - iv := v.Interface() - return iv.(Unmarshaler).Unmarshal(raw) - } - - obuf := o.buf - oi := o.index - o.buf = raw - o.index = 0 - - err = o.unmarshalType(p.stype, p.sprop, is_group, bas) - - o.buf = obuf - o.index = oi - - return err -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go deleted file mode 100644 index cd826e9b1ac42d7e58064f7929994d4431272cdf..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/encode.go +++ /dev/null @@ -1,1286 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "errors" - "fmt" - "reflect" - "sort" -) - -// RequiredNotSetError is the error returned if Marshal is called with -// a protocol buffer struct whose required fields have not -// all been initialized. It is also the error returned if Unmarshal is -// called with an encoded protocol buffer that does not include all the -// required fields. -// -// When printed, RequiredNotSetError reports the first unset required field in a -// message. If the field cannot be precisely determined, it is reported as -// "{Unknown}". -type RequiredNotSetError struct { - field string -} - -func (e *RequiredNotSetError) Error() string { - return fmt.Sprintf("proto: required field %q not set", e.field) -} - -var ( - // errRepeatedHasNil is the error returned if Marshal is called with - // a struct with a repeated field containing a nil element. - errRepeatedHasNil = errors.New("proto: repeated field has nil element") - - // ErrNil is the error returned if Marshal is called with nil. - ErrNil = errors.New("proto: Marshal called with nil") -) - -// The fundamental encoders that put bytes on the wire. -// Those that take integer types all accept uint64 and are -// therefore of type valueEncoder. - -const maxVarintBytes = 10 // maximum length of a varint - -// EncodeVarint returns the varint encoding of x. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -// Not used by the package itself, but helpful to clients -// wishing to use the same encoding. -func EncodeVarint(x uint64) []byte { - var buf [maxVarintBytes]byte - var n int - for n = 0; x > 127; n++ { - buf[n] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - buf[n] = uint8(x) - n++ - return buf[0:n] -} - -// EncodeVarint writes a varint-encoded integer to the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) EncodeVarint(x uint64) error { - for x >= 1<<7 { - p.buf = append(p.buf, uint8(x&0x7f|0x80)) - x >>= 7 - } - p.buf = append(p.buf, uint8(x)) - return nil -} - -func sizeVarint(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} - -// EncodeFixed64 writes a 64-bit integer to the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) EncodeFixed64(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24), - uint8(x>>32), - uint8(x>>40), - uint8(x>>48), - uint8(x>>56)) - return nil -} - -func sizeFixed64(x uint64) int { - return 8 -} - -// EncodeFixed32 writes a 32-bit integer to the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) EncodeFixed32(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24)) - return nil -} - -func sizeFixed32(x uint64) int { - return 4 -} - -// EncodeZigzag64 writes a zigzag-encoded 64-bit integer -// to the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) EncodeZigzag64(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} - -func sizeZigzag64(x uint64) int { - return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} - -// EncodeZigzag32 writes a zigzag-encoded 32-bit integer -// to the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) EncodeZigzag32(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -func sizeZigzag32(x uint64) int { - return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) EncodeRawBytes(b []byte) error { - p.EncodeVarint(uint64(len(b))) - p.buf = append(p.buf, b...) - return nil -} - -func sizeRawBytes(b []byte) int { - return sizeVarint(uint64(len(b))) + - len(b) -} - -// EncodeStringBytes writes an encoded string to the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) EncodeStringBytes(s string) error { - p.EncodeVarint(uint64(len(s))) - p.buf = append(p.buf, s...) - return nil -} - -func sizeStringBytes(s string) int { - return sizeVarint(uint64(len(s))) + - len(s) -} - -// Marshaler is the interface representing objects that can marshal themselves. -type Marshaler interface { - Marshal() ([]byte, error) -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, returning the data. -func Marshal(pb Message) ([]byte, error) { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - return m.Marshal() - } - p := NewBuffer(nil) - err := p.Marshal(pb) - var state errorState - if err != nil && !state.shouldContinue(err, nil) { - return nil, err - } - if p.buf == nil && err == nil { - // Return a non-nil slice on success. - return []byte{}, nil - } - return p.buf, err -} - -// Marshal takes the protocol buffer -// and encodes it into the wire format, writing the result to the -// Buffer. -func (p *Buffer) Marshal(pb Message) error { - // Can the object marshal itself? - if m, ok := pb.(Marshaler); ok { - data, err := m.Marshal() - if err != nil { - return err - } - p.buf = append(p.buf, data...) - return nil - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return ErrNil - } - if err == nil { - err = p.enc_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - stats.Encode++ - } - - return err -} - -// Size returns the encoded size of a protocol buffer. -func Size(pb Message) (n int) { - // Can the object marshal itself? If so, Size is slow. - // TODO: add Size to Marshaler, or add a Sizer interface. - if m, ok := pb.(Marshaler); ok { - b, _ := m.Marshal() - return len(b) - } - - t, base, err := getbase(pb) - if structPointer_IsNil(base) { - return 0 - } - if err == nil { - n = size_struct(GetProperties(t.Elem()), base) - } - - if collectStats { - stats.Size++ - } - - return -} - -// Individual type encoders. - -// Encode a bool. -func (o *Buffer) enc_bool(p *Properties, base structPointer) error { - v := *structPointer_Bool(base, p.field) - if v == nil { - return ErrNil - } - x := 0 - if *v { - x = 1 - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { - v := *structPointer_BoolVal(base, p.field) - if !v { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, 1) - return nil -} - -func size_bool(p *Properties, base structPointer) int { - v := *structPointer_Bool(base, p.field) - if v == nil { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -func size_proto3_bool(p *Properties, base structPointer) int { - v := *structPointer_BoolVal(base, p.field) - if !v { - return 0 - } - return len(p.tagcode) + 1 // each bool takes exactly one byte -} - -// Encode an int32. -func (o *Buffer) enc_int32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_int32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range - if x == 0 { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode a uint32. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return ErrNil - } - x := word32_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, uint64(x)) - return nil -} - -func size_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32(base, p.field) - if word32_IsNil(v) { - return 0 - } - x := word32_Get(v) - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -func size_proto3_uint32(p *Properties, base structPointer) (n int) { - v := structPointer_Word32Val(base, p.field) - x := word32Val_Get(v) - if x == 0 { - return 0 - } - n += len(p.tagcode) - n += p.valSize(uint64(x)) - return -} - -// Encode an int64. -func (o *Buffer) enc_int64(p *Properties, base structPointer) error { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return ErrNil - } - x := word64_Get(v) - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, x) - return nil -} - -func size_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64(base, p.field) - if word64_IsNil(v) { - return 0 - } - x := word64_Get(v) - n += len(p.tagcode) - n += p.valSize(x) - return -} - -func size_proto3_int64(p *Properties, base structPointer) (n int) { - v := structPointer_Word64Val(base, p.field) - x := word64Val_Get(v) - if x == 0 { - return 0 - } - n += len(p.tagcode) - n += p.valSize(x) - return -} - -// Encode a string. -func (o *Buffer) enc_string(p *Properties, base structPointer) error { - v := *structPointer_String(base, p.field) - if v == nil { - return ErrNil - } - x := *v - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(x) - return nil -} - -func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { - v := *structPointer_StringVal(base, p.field) - if v == "" { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(v) - return nil -} - -func size_string(p *Properties, base structPointer) (n int) { - v := *structPointer_String(base, p.field) - if v == nil { - return 0 - } - x := *v - n += len(p.tagcode) - n += sizeStringBytes(x) - return -} - -func size_proto3_string(p *Properties, base structPointer) (n int) { - v := *structPointer_StringVal(base, p.field) - if v == "" { - return 0 - } - n += len(p.tagcode) - n += sizeStringBytes(v) - return -} - -// All protocol buffer fields are nillable, but be careful. -func isNil(v reflect.Value) bool { - switch v.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return v.IsNil() - } - return false -} - -// Encode a message struct. -func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { - var state errorState - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return ErrNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - return nil - } - - o.buf = append(o.buf, p.tagcode...) - return o.enc_len_struct(p.sprop, structp, &state) -} - -func size_struct_message(p *Properties, base structPointer) int { - structp := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(structp) { - return 0 - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n0 := len(p.tagcode) - n1 := sizeRawBytes(data) - return n0 + n1 - } - - n0 := len(p.tagcode) - n1 := size_struct(p.sprop, structp) - n2 := sizeVarint(uint64(n1)) // size of encoded length - return n0 + n1 + n2 -} - -// Encode a group struct. -func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { - var state errorState - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return ErrNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - err := o.enc_struct(p.sprop, b) - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return state.err -} - -func size_struct_group(p *Properties, base structPointer) (n int) { - b := structPointer_GetStructPointer(base, p.field) - if structPointer_IsNil(b) { - return 0 - } - - n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) - n += size_struct(p.sprop, b) - n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) - return -} - -// Encode a slice of bools ([]bool). -func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - for _, x := range s { - o.buf = append(o.buf, p.tagcode...) - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_bool(p *Properties, base structPointer) int { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - return l * (len(p.tagcode) + 1) // each bool takes exactly one byte -} - -// Encode a slice of bools ([]bool) in packed format. -func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(l)) // each bool takes exactly one byte - for _, x := range s { - v := uint64(0) - if x { - v = 1 - } - p.valEnc(o, v) - } - return nil -} - -func size_slice_packed_bool(p *Properties, base structPointer) (n int) { - s := *structPointer_BoolSlice(base, p.field) - l := len(s) - if l == 0 { - return 0 - } - n += len(p.tagcode) - n += sizeVarint(uint64(l)) - n += l // each bool takes exactly one byte - return -} - -// Encode a slice of bytes ([]byte). -func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if s == nil { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { - return ErrNil - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(s) - return nil -} - -func size_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if s == nil { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { - s := *structPointer_Bytes(base, p.field) - if len(s) == 0 { - return 0 - } - n += len(p.tagcode) - n += sizeRawBytes(s) - return -} - -// Encode a slice of int32s ([]int32). -func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of int32s ([]int32) in packed format. -func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - p.valEnc(buf, uint64(x)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - x := int32(s.Index(i)) // permit sign extension to use full 64-bit range - bufSize += p.valSize(uint64(x)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of uint32s ([]uint32). -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - x := s.Index(i) - p.valEnc(o, uint64(x)) - } - return nil -} - -func size_slice_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - x := s.Index(i) - n += p.valSize(uint64(x)) - } - return -} - -// Encode a slice of uint32s ([]uint32) in packed format. -// Exactly the same as int32, except for no sign extension. -func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, uint64(s.Index(i))) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { - s := structPointer_Word32Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(uint64(s.Index(i))) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of int64s ([]int64). -func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - p.valEnc(o, s.Index(i)) - } - return nil -} - -func size_slice_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - for i := 0; i < l; i++ { - n += len(p.tagcode) - n += p.valSize(s.Index(i)) - } - return -} - -// Encode a slice of int64s ([]int64) in packed format. -func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return ErrNil - } - // TODO: Reuse a Buffer. - buf := NewBuffer(nil) - for i := 0; i < l; i++ { - p.valEnc(buf, s.Index(i)) - } - - o.buf = append(o.buf, p.tagcode...) - o.EncodeVarint(uint64(len(buf.buf))) - o.buf = append(o.buf, buf.buf...) - return nil -} - -func size_slice_packed_int64(p *Properties, base structPointer) (n int) { - s := structPointer_Word64Slice(base, p.field) - l := s.Len() - if l == 0 { - return 0 - } - var bufSize int - for i := 0; i < l; i++ { - bufSize += p.valSize(s.Index(i)) - } - - n += len(p.tagcode) - n += sizeVarint(uint64(bufSize)) - n += bufSize - return -} - -// Encode a slice of slice of bytes ([][]byte). -func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return ErrNil - } - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(ss[i]) - } - return nil -} - -func size_slice_slice_byte(p *Properties, base structPointer) (n int) { - ss := *structPointer_BytesSlice(base, p.field) - l := len(ss) - if l == 0 { - return 0 - } - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeRawBytes(ss[i]) - } - return -} - -// Encode a slice of strings ([]string). -func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - for i := 0; i < l; i++ { - o.buf = append(o.buf, p.tagcode...) - o.EncodeStringBytes(ss[i]) - } - return nil -} - -func size_slice_string(p *Properties, base structPointer) (n int) { - ss := *structPointer_StringSlice(base, p.field) - l := len(ss) - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - n += sizeStringBytes(ss[i]) - } - return -} - -// Encode a slice of message structs ([]*struct). -func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return errRepeatedHasNil - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, err := m.Marshal() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - o.buf = append(o.buf, p.tagcode...) - o.EncodeRawBytes(data) - continue - } - - o.buf = append(o.buf, p.tagcode...) - err := o.enc_len_struct(p.sprop, structp, &state) - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - } - return state.err -} - -func size_slice_struct_message(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - n += l * len(p.tagcode) - for i := 0; i < l; i++ { - structp := s.Index(i) - if structPointer_IsNil(structp) { - return // return the size up to this point - } - - // Can the object marshal itself? - if p.isMarshaler { - m := structPointer_Interface(structp, p.stype).(Marshaler) - data, _ := m.Marshal() - n += len(p.tagcode) - n += sizeRawBytes(data) - continue - } - - n0 := size_struct(p.sprop, structp) - n1 := sizeVarint(uint64(n0)) // size of encoded length - n += n0 + n1 - } - return -} - -// Encode a slice of group structs ([]*struct). -func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { - var state errorState - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return errRepeatedHasNil - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) - - err := o.enc_struct(p.sprop, b) - - if err != nil && !state.shouldContinue(err, nil) { - if err == ErrNil { - return errRepeatedHasNil - } - return err - } - - o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) - } - return state.err -} - -func size_slice_struct_group(p *Properties, base structPointer) (n int) { - s := structPointer_StructPointerSlice(base, p.field) - l := s.Len() - - n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) - n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) - for i := 0; i < l; i++ { - b := s.Index(i) - if structPointer_IsNil(b) { - return // return size up to this point - } - - n += size_struct(p.sprop, b) - } - return -} - -// Encode an extension map. -func (o *Buffer) enc_map(p *Properties, base structPointer) error { - v := *structPointer_ExtMap(base, p.field) - if err := encodeExtensionMap(v); err != nil { - return err - } - // Fast-path for common cases: zero or one extensions. - if len(v) <= 1 { - for _, e := range v { - o.buf = append(o.buf, e.enc...) - } - return nil - } - - // Sort keys to provide a deterministic encoding. - keys := make([]int, 0, len(v)) - for k := range v { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - o.buf = append(o.buf, v[int32(k)].enc...) - } - return nil -} - -func size_map(p *Properties, base structPointer) int { - v := *structPointer_ExtMap(base, p.field) - return sizeExtensionMap(v) -} - -// Encode a map field. -func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { - var state errorState // XXX: or do we need to plumb this through? - - /* - A map defined as - map<key_type, value_type> map_field = N; - is encoded in the same way as - message MapFieldEntry { - key_type key = 1; - value_type value = 2; - } - repeated MapFieldEntry map_field = N; - */ - - v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V - if v.Len() == 0 { - return nil - } - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - enc := func() error { - if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { - return err - } - if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil { - return err - } - return nil - } - - keys := v.MapKeys() - sort.Sort(mapKeys(keys)) - for _, key := range keys { - val := v.MapIndex(key) - - keycopy.Set(key) - valcopy.Set(val) - - o.buf = append(o.buf, p.tagcode...) - if err := o.enc_len_thing(enc, &state); err != nil { - return err - } - } - return nil -} - -func size_new_map(p *Properties, base structPointer) int { - v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V - - keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) - - n := 0 - for _, key := range v.MapKeys() { - val := v.MapIndex(key) - keycopy.Set(key) - valcopy.Set(val) - - // Tag codes are two bytes per map entry. - n += 2 - n += p.mkeyprop.size(p.mkeyprop, keybase) - n += p.mvalprop.size(p.mvalprop, valbase) - } - return n -} - -// mapEncodeScratch returns a new reflect.Value matching the map's value type, -// and a structPointer suitable for passing to an encoder or sizer. -func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { - // Prepare addressable doubly-indirect placeholders for the key and value types. - // This is needed because the element-type encoders expect **T, but the map iteration produces T. - - keycopy = reflect.New(mapType.Key()).Elem() // addressable K - keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K - keyptr.Set(keycopy.Addr()) // - keybase = toStructPointer(keyptr.Addr()) // **K - - // Value types are more varied and require special handling. - switch mapType.Elem().Kind() { - case reflect.Slice: - // []byte - var dummy []byte - valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte - valbase = toStructPointer(valcopy.Addr()) - case reflect.Ptr: - // message; the generated field type is map[K]*Msg (so V is *Msg), - // so we only need one level of indirection. - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valbase = toStructPointer(valcopy.Addr()) - default: - // everything else - valcopy = reflect.New(mapType.Elem()).Elem() // addressable V - valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V - valptr.Set(valcopy.Addr()) // - valbase = toStructPointer(valptr.Addr()) // **V - } - return -} - -// Encode a struct. -func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { - var state errorState - // Encode fields in tag order so that decoders may use optimizations - // that depend on the ordering. - // https://developers.google.com/protocol-buffers/docs/encoding#order - for _, i := range prop.order { - p := prop.Prop[i] - if p.enc != nil { - err := p.enc(o, p, base) - if err != nil { - if err == ErrNil { - if p.Required && state.err == nil { - state.err = &RequiredNotSetError{p.Name} - } - } else if err == errRepeatedHasNil { - // Give more context to nil values in repeated fields. - return errors.New("repeated field " + p.OrigName + " has nil element") - } else if !state.shouldContinue(err, p) { - return err - } - } - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - if len(v) > 0 { - o.buf = append(o.buf, v...) - } - } - - return state.err -} - -func size_struct(prop *StructProperties, base structPointer) (n int) { - for _, i := range prop.order { - p := prop.Prop[i] - if p.size != nil { - n += p.size(p, base) - } - } - - // Add unrecognized fields at the end. - if prop.unrecField.IsValid() { - v := *structPointer_Bytes(base, prop.unrecField) - n += len(v) - } - - return -} - -var zeroes [20]byte // longer than any conceivable sizeVarint - -// Encode a struct, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { - return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) -} - -// Encode something, preceded by its encoded length (as a varint). -func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { - iLen := len(o.buf) - o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length - iMsg := len(o.buf) - err := enc() - if err != nil && !state.shouldContinue(err, nil) { - return err - } - lMsg := len(o.buf) - iMsg - lLen := sizeVarint(uint64(lMsg)) - switch x := lLen - (iMsg - iLen); { - case x > 0: // actual length is x bytes larger than the space we reserved - // Move msg x bytes right. - o.buf = append(o.buf, zeroes[:x]...) - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - case x < 0: // actual length is x bytes smaller than the space we reserved - // Move msg x bytes left. - copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) - o.buf = o.buf[:len(o.buf)+x] // x is negative - } - // Encode the length in the reserved space. - o.buf = o.buf[:iLen] - o.EncodeVarint(uint64(lMsg)) - o.buf = o.buf[:len(o.buf)+lMsg] - return state.err -} - -// errorState maintains the first error that occurs and updates that error -// with additional context. -type errorState struct { - err error -} - -// shouldContinue reports whether encoding should continue upon encountering the -// given error. If the error is RequiredNotSetError, shouldContinue returns true -// and, if this is the first appearance of that error, remembers it for future -// reporting. -// -// If prop is not nil, it may update any error with additional context about the -// field with the error. -func (s *errorState) shouldContinue(err error, prop *Properties) bool { - // Ignore unset required fields. - reqNotSet, ok := err.(*RequiredNotSetError) - if !ok { - return false - } - if s.err == nil { - if prop != nil { - err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} - } - s.err = err - } - return true -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go deleted file mode 100644 index d8673a3e97aef00f2becedba88ed12e6fcb6ee57..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/equal.go +++ /dev/null @@ -1,256 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer comparison. -// TODO: MessageSet. - -package proto - -import ( - "bytes" - "log" - "reflect" - "strings" -) - -/* -Equal returns true iff protocol buffers a and b are equal. -The arguments must both be pointers to protocol buffer structs. - -Equality is defined in this way: - - Two messages are equal iff they are the same type, - corresponding fields are equal, unknown field sets - are equal, and extensions sets are equal. - - Two set scalar fields are equal iff their values are equal. - If the fields are of a floating-point type, remember that - NaN != x for all x, including NaN. - - Two repeated fields are equal iff their lengths are the same, - and their corresponding elements are equal (a "bytes" field, - although represented by []byte, is not a repeated field) - - Two unset fields are equal. - - Two unknown field sets are equal if their current - encoded state is equal. - - Two extension sets are equal iff they have corresponding - elements that are pairwise equal. - - Every other combination of things are not equal. - -The return value is undefined if a and b are not protocol buffers. -*/ -func Equal(a, b Message) bool { - if a == nil || b == nil { - return a == b - } - v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) - if v1.Type() != v2.Type() { - return false - } - if v1.Kind() == reflect.Ptr { - if v1.IsNil() { - return v2.IsNil() - } - if v2.IsNil() { - return false - } - v1, v2 = v1.Elem(), v2.Elem() - } - if v1.Kind() != reflect.Struct { - return false - } - return equalStruct(v1, v2) -} - -// v1 and v2 are known to have the same type. -func equalStruct(v1, v2 reflect.Value) bool { - for i := 0; i < v1.NumField(); i++ { - f := v1.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - f1, f2 := v1.Field(i), v2.Field(i) - if f.Type.Kind() == reflect.Ptr { - if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { - // both unset - continue - } else if n1 != n2 { - // set/unset mismatch - return false - } - b1, ok := f1.Interface().(raw) - if ok { - b2 := f2.Interface().(raw) - // RawMessage - if !bytes.Equal(b1.Bytes(), b2.Bytes()) { - return false - } - continue - } - f1, f2 = f1.Elem(), f2.Elem() - } - if !equalAny(f1, f2) { - return false - } - } - - if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_extensions") - if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { - return false - } - } - - uf := v1.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return true - } - - u1 := uf.Bytes() - u2 := v2.FieldByName("XXX_unrecognized").Bytes() - if !bytes.Equal(u1, u2) { - return false - } - - return true -} - -// v1 and v2 are known to have the same type. -func equalAny(v1, v2 reflect.Value) bool { - if v1.Type() == protoMessageType { - m1, _ := v1.Interface().(Message) - m2, _ := v2.Interface().(Message) - return Equal(m1, m2) - } - switch v1.Kind() { - case reflect.Bool: - return v1.Bool() == v2.Bool() - case reflect.Float32, reflect.Float64: - return v1.Float() == v2.Float() - case reflect.Int32, reflect.Int64: - return v1.Int() == v2.Int() - case reflect.Map: - if v1.Len() != v2.Len() { - return false - } - for _, key := range v1.MapKeys() { - val2 := v2.MapIndex(key) - if !val2.IsValid() { - // This key was not found in the second map. - return false - } - if !equalAny(v1.MapIndex(key), val2) { - return false - } - } - return true - case reflect.Ptr: - return equalAny(v1.Elem(), v2.Elem()) - case reflect.Slice: - if v1.Type().Elem().Kind() == reflect.Uint8 { - // short circuit: []byte - if v1.IsNil() != v2.IsNil() { - return false - } - return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) - } - - if v1.Len() != v2.Len() { - return false - } - for i := 0; i < v1.Len(); i++ { - if !equalAny(v1.Index(i), v2.Index(i)) { - return false - } - } - return true - case reflect.String: - return v1.Interface().(string) == v2.Interface().(string) - case reflect.Struct: - return equalStruct(v1, v2) - case reflect.Uint32, reflect.Uint64: - return v1.Uint() == v2.Uint() - } - - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to compare %v", v1) - return false -} - -// base is the struct type that the extensions are based on. -// em1 and em2 are extension maps. -func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool { - if len(em1) != len(em2) { - return false - } - - for extNum, e1 := range em1 { - e2, ok := em2[extNum] - if !ok { - return false - } - - m1, m2 := e1.value, e2.value - - if m1 != nil && m2 != nil { - // Both are unencoded. - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { - return false - } - continue - } - - // At least one is encoded. To do a semantically correct comparison - // we need to unmarshal them first. - var desc *ExtensionDesc - if m := extensionMaps[base]; m != nil { - desc = m[extNum] - } - if desc == nil { - log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - continue - } - var err error - if m1 == nil { - m1, err = decodeExtension(e1.enc, desc) - } - if m2 == nil && err == nil { - m2, err = decodeExtension(e2.enc, desc) - } - if err != nil { - // The encoded form is invalid. - log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) - return false - } - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) { - return false - } - } - - return true -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go deleted file mode 100644 index 5f62dff2474863632742a26a8c225590b47413f2..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/extensions.go +++ /dev/null @@ -1,362 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Types and routines for supporting protocol buffer extensions. - */ - -import ( - "errors" - "fmt" - "reflect" - "strconv" - "sync" -) - -// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. -var ErrMissingExtension = errors.New("proto: missing extension") - -// ExtensionRange represents a range of message extensions for a protocol buffer. -// Used in code generated by the protocol compiler. -type ExtensionRange struct { - Start, End int32 // both inclusive -} - -// extendableProto is an interface implemented by any protocol buffer that may be extended. -type extendableProto interface { - Message - ExtensionRangeArray() []ExtensionRange - ExtensionMap() map[int32]Extension -} - -var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() - -// ExtensionDesc represents an extension specification. -// Used in generated code from the protocol compiler. -type ExtensionDesc struct { - ExtendedType Message // nil pointer to the type that is being extended - ExtensionType interface{} // nil pointer to the extension type - Field int32 // field number - Name string // fully-qualified name of extension, for text formatting - Tag string // protobuf tag style -} - -func (ed *ExtensionDesc) repeated() bool { - t := reflect.TypeOf(ed.ExtensionType) - return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 -} - -// Extension represents an extension in a message. -type Extension struct { - // When an extension is stored in a message using SetExtension - // only desc and value are set. When the message is marshaled - // enc will be set to the encoded form of the message. - // - // When a message is unmarshaled and contains extensions, each - // extension will have only enc set. When such an extension is - // accessed using GetExtension (or GetExtensions) desc and value - // will be set. - desc *ExtensionDesc - value interface{} - enc []byte -} - -// SetRawExtension is for testing only. -func SetRawExtension(base extendableProto, id int32, b []byte) { - base.ExtensionMap()[id] = Extension{enc: b} -} - -// isExtensionField returns true iff the given field number is in an extension range. -func isExtensionField(pb extendableProto, field int32) bool { - for _, er := range pb.ExtensionRangeArray() { - if er.Start <= field && field <= er.End { - return true - } - } - return false -} - -// checkExtensionTypes checks that the given extension is valid for pb. -func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { - // Check the extended type. - if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b { - return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) - } - // Check the range. - if !isExtensionField(pb, extension.Field) { - return errors.New("proto: bad extension number; not in declared ranges") - } - return nil -} - -// extPropKey is sufficient to uniquely identify an extension. -type extPropKey struct { - base reflect.Type - field int32 -} - -var extProp = struct { - sync.RWMutex - m map[extPropKey]*Properties -}{ - m: make(map[extPropKey]*Properties), -} - -func extensionProperties(ed *ExtensionDesc) *Properties { - key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} - - extProp.RLock() - if prop, ok := extProp.m[key]; ok { - extProp.RUnlock() - return prop - } - extProp.RUnlock() - - extProp.Lock() - defer extProp.Unlock() - // Check again. - if prop, ok := extProp.m[key]; ok { - return prop - } - - prop := new(Properties) - prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) - extProp.m[key] = prop - return prop -} - -// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m. -func encodeExtensionMap(m map[int32]Extension) error { - for k, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - p := NewBuffer(nil) - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - if err := props.enc(p, props, toStructPointer(x)); err != nil { - return err - } - e.enc = p.buf - m[k] = e - } - return nil -} - -func sizeExtensionMap(m map[int32]Extension) (n int) { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - et := reflect.TypeOf(e.desc.ExtensionType) - props := extensionProperties(e.desc) - - // If e.value has type T, the encoder expects a *struct{ X T }. - // Pass a *T with a zero field and hope it all works out. - x := reflect.New(et) - x.Elem().Set(reflect.ValueOf(e.value)) - n += props.size(props, toStructPointer(x)) - } - return -} - -// HasExtension returns whether the given extension is present in pb. -func HasExtension(pb extendableProto, extension *ExtensionDesc) bool { - // TODO: Check types, field numbers, etc.? - _, ok := pb.ExtensionMap()[extension.Field] - return ok -} - -// ClearExtension removes the given extension from pb. -func ClearExtension(pb extendableProto, extension *ExtensionDesc) { - // TODO: Check types, field numbers, etc.? - delete(pb.ExtensionMap(), extension.Field) -} - -// GetExtension parses and returns the given extension of pb. -// If the extension is not present it returns ErrMissingExtension. -func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) { - if err := checkExtensionTypes(pb, extension); err != nil { - return nil, err - } - - emap := pb.ExtensionMap() - e, ok := emap[extension.Field] - if !ok { - return nil, ErrMissingExtension - } - if e.value != nil { - // Already decoded. Check the descriptor, though. - if e.desc != extension { - // This shouldn't happen. If it does, it means that - // GetExtension was called twice with two different - // descriptors with the same field number. - return nil, errors.New("proto: descriptor conflict") - } - return e.value, nil - } - - v, err := decodeExtension(e.enc, extension) - if err != nil { - return nil, err - } - - // Remember the decoded version and drop the encoded version. - // That way it is safe to mutate what we return. - e.value = v - e.desc = extension - e.enc = nil - emap[extension.Field] = e - return e.value, nil -} - -// decodeExtension decodes an extension encoded in b. -func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - o := NewBuffer(b) - - t := reflect.TypeOf(extension.ExtensionType) - rep := extension.repeated() - - props := extensionProperties(extension) - - // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate a "field" to store the pointer/slice itself; the - // pointer/slice will be stored here. We pass - // the address of this field to props.dec. - // This passes a zero field and a *t and lets props.dec - // interpret it as a *struct{ x t }. - value := reflect.New(t).Elem() - - for { - // Discard wire type and field number varint. It isn't needed. - if _, err := o.DecodeVarint(); err != nil { - return nil, err - } - - if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { - return nil, err - } - - if !rep || o.index >= len(o.buf) { - break - } - } - return value.Interface(), nil -} - -// GetExtensions returns a slice of the extensions present in pb that are also listed in es. -// The returned slice has the same length as es; missing extensions will appear as nil elements. -func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, ok := pb.(extendableProto) - if !ok { - err = errors.New("proto: not an extendable proto") - return - } - extensions = make([]interface{}, len(es)) - for i, e := range es { - extensions[i], err = GetExtension(epb, e) - if err == ErrMissingExtension { - err = nil - } - if err != nil { - return - } - } - return -} - -// SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error { - if err := checkExtensionTypes(pb, extension); err != nil { - return err - } - typ := reflect.TypeOf(extension.ExtensionType) - if typ != reflect.TypeOf(value) { - return errors.New("proto: bad extension value type") - } - // nil extension values need to be caught early, because the - // encoder can't distinguish an ErrNil due to a nil extension - // from an ErrNil due to a missing field. Extensions are - // always optional, so the encoder would just swallow the error - // and drop all the extensions from the encoded message. - if reflect.ValueOf(value).IsNil() { - return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) - } - - pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value} - return nil -} - -// A global registry of extensions. -// The generated code will register the generated descriptors by calling RegisterExtension. - -var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) - -// RegisterExtension is called from the generated code. -func RegisterExtension(desc *ExtensionDesc) { - st := reflect.TypeOf(desc.ExtendedType).Elem() - m := extensionMaps[st] - if m == nil { - m = make(map[int32]*ExtensionDesc) - extensionMaps[st] = m - } - if _, ok := m[desc.Field]; ok { - panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) - } - m[desc.Field] = desc -} - -// RegisteredExtensions returns a map of the registered extensions of a -// protocol buffer struct, indexed by the extension number. -// The argument pb should be a nil pointer to the struct type. -func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { - return extensionMaps[reflect.TypeOf(pb).Elem()] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go deleted file mode 100644 index f81052f2aeb11e2711eccfe6649dddfc732469e4..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/lib.go +++ /dev/null @@ -1,759 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* - Package proto converts data structures to and from the wire format of - protocol buffers. It works in concert with the Go source code generated - for .proto files by the protocol compiler. - - A summary of the properties of the protocol buffer interface - for a protocol buffer variable v: - - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. - - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Marshal and Unmarshal are functions to encode and decode the wire format. - - The simplest way to describe this is to see an example. - Given file test.proto, containing - - package example; - - enum FOO { X = 17; } - - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } - } - - The resulting file, test.pb.go, is: - - package example - - import proto "github.com/golang/protobuf/proto" - import math "math" - - type FOO int32 - const ( - FOO_X FOO = 17 - ) - var FOO_name = map[int32]string{ - 17: "X", - } - var FOO_value = map[string]int32{ - "X": 17, - } - - func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p - } - func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) - } - func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data) - if err != nil { - return err - } - *x = FOO(value) - return nil - } - - type Test struct { - Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` - Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` - Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` - Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` - XXX_unrecognized []byte `json:"-"` - } - func (m *Test) Reset() { *m = Test{} } - func (m *Test) String() string { return proto.CompactTextString(m) } - func (*Test) ProtoMessage() {} - const Default_Test_Type int32 = 77 - - func (m *Test) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" - } - - func (m *Test) GetType() int32 { - if m != nil && m.Type != nil { - return *m.Type - } - return Default_Test_Type - } - - func (m *Test) GetOptionalgroup() *Test_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil - } - - type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` - } - func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } - func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - - func (m *Test_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" - } - - func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) - } - - To create and play with a Test object: - - package main - - import ( - "log" - - "github.com/golang/protobuf/proto" - pb "./example.pb" - ) - - func main() { - test := &pb.Test{ - Label: proto.String("hello"), - Type: proto.Int32(17), - Optionalgroup: &pb.Test_OptionalGroup{ - RequiredField: proto.String("good bye"), - }, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &pb.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // etc. - } -*/ -package proto - -import ( - "encoding/json" - "fmt" - "log" - "reflect" - "strconv" - "sync" -) - -// Message is implemented by generated protocol buffer messages. -type Message interface { - Reset() - String() string - ProtoMessage() -} - -// Stats records allocation details about the protocol buffer encoders -// and decoders. Useful for tuning the library itself. -type Stats struct { - Emalloc uint64 // mallocs in encode - Dmalloc uint64 // mallocs in decode - Encode uint64 // number of encodes - Decode uint64 // number of decodes - Chit uint64 // number of cache hits - Cmiss uint64 // number of cache misses - Size uint64 // number of sizes -} - -// Set to true to enable stats collection. -const collectStats = false - -var stats Stats - -// GetStats returns a copy of the global Stats structure. -func GetStats() Stats { return stats } - -// A Buffer is a buffer manager for marshaling and unmarshaling -// protocol buffers. It may be reused between invocations to -// reduce memory usage. It is not necessary to use a Buffer; -// the global functions Marshal and Unmarshal create a -// temporary Buffer and are fine for most applications. -type Buffer struct { - buf []byte // encode/decode byte stream - index int // write point - - // pools of basic types to amortize allocation. - bools []bool - uint32s []uint32 - uint64s []uint64 - - // extra pools, only used with pointer_reflect.go - int32s []int32 - int64s []int64 - float32s []float32 - float64s []float64 -} - -// NewBuffer allocates a new Buffer and initializes its internal data to -// the contents of the argument slice. -func NewBuffer(e []byte) *Buffer { - return &Buffer{buf: e} -} - -// Reset resets the Buffer, ready for marshaling a new protocol buffer. -func (p *Buffer) Reset() { - p.buf = p.buf[0:0] // for reading/writing - p.index = 0 // for reading -} - -// SetBuf replaces the internal buffer with the slice, -// ready for unmarshaling the contents of the slice. -func (p *Buffer) SetBuf(s []byte) { - p.buf = s - p.index = 0 -} - -// Bytes returns the contents of the Buffer. -func (p *Buffer) Bytes() []byte { return p.buf } - -/* - * Helper routines for simplifying the creation of optional fields of basic type. - */ - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { - return &v -} - -// Int32 is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it. -func Int32(v int32) *int32 { - return &v -} - -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int32 { - p := new(int32) - *p = int32(v) - return p -} - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { - return &v -} - -// Float32 is a helper routine that allocates a new float32 value -// to store v and returns a pointer to it. -func Float32(v float32) *float32 { - return &v -} - -// Float64 is a helper routine that allocates a new float64 value -// to store v and returns a pointer to it. -func Float64(v float64) *float64 { - return &v -} - -// Uint32 is a helper routine that allocates a new uint32 value -// to store v and returns a pointer to it. -func Uint32(v uint32) *uint32 { - return &v -} - -// Uint64 is a helper routine that allocates a new uint64 value -// to store v and returns a pointer to it. -func Uint64(v uint64) *uint64 { - return &v -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { - return &v -} - -// EnumName is a helper function to simplify printing protocol buffer enums -// by name. Given an enum map and a value, it returns a useful string. -func EnumName(m map[int32]string, v int32) string { - s, ok := m[v] - if ok { - return s - } - return strconv.Itoa(int(v)) -} - -// UnmarshalJSONEnum is a helper function to simplify recovering enum int values -// from their JSON-encoded representation. Given a map from the enum's symbolic -// names to its int values, and a byte buffer containing the JSON-encoded -// value, it returns an int32 that can be cast to the enum type by the caller. -// -// The function can deal with both JSON representations, numeric and symbolic. -func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { - if data[0] == '"' { - // New style: enums are strings. - var repr string - if err := json.Unmarshal(data, &repr); err != nil { - return -1, err - } - val, ok := m[repr] - if !ok { - return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) - } - return val, nil - } - // Old style: enums are ints. - var val int32 - if err := json.Unmarshal(data, &val); err != nil { - return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) - } - return val, nil -} - -// DebugPrint dumps the encoded data in b in a debugging format with a header -// including the string s. Used in testing but made available for general debugging. -func (o *Buffer) DebugPrint(s string, b []byte) { - var u uint64 - - obuf := o.buf - index := o.index - o.buf = b - o.index = 0 - depth := 0 - - fmt.Printf("\n--- %s ---\n", s) - -out: - for { - for i := 0; i < depth; i++ { - fmt.Print(" ") - } - - index := o.index - if index == len(o.buf) { - break - } - - op, err := o.DecodeVarint() - if err != nil { - fmt.Printf("%3d: fetching op err %v\n", index, err) - break out - } - tag := op >> 3 - wire := op & 7 - - switch wire { - default: - fmt.Printf("%3d: t=%3d unknown wire=%d\n", - index, tag, wire) - break out - - case WireBytes: - var r []byte - - r, err = o.DecodeRawBytes(false) - if err != nil { - break out - } - fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) - if len(r) <= 6 { - for i := 0; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } else { - for i := 0; i < 3; i++ { - fmt.Printf(" %.2x", r[i]) - } - fmt.Printf(" ..") - for i := len(r) - 3; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } - fmt.Printf("\n") - - case WireFixed32: - u, err = o.DecodeFixed32() - if err != nil { - fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) - - case WireFixed64: - u, err = o.DecodeFixed64() - if err != nil { - fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) - break - - case WireVarint: - u, err = o.DecodeVarint() - if err != nil { - fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) - - case WireStartGroup: - if err != nil { - fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d start\n", index, tag) - depth++ - - case WireEndGroup: - depth-- - if err != nil { - fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d end\n", index, tag) - } - } - - if depth != 0 { - fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth) - } - fmt.Printf("\n") - - o.buf = obuf - o.index = index -} - -// SetDefaults sets unset protocol buffer fields to their default values. -// It only modifies fields that are both unset and have defined defaults. -// It recursively sets default values in any non-nil sub-messages. -func SetDefaults(pb Message) { - setDefaults(reflect.ValueOf(pb), true, false) -} - -// v is a pointer to a struct. -func setDefaults(v reflect.Value, recur, zeros bool) { - v = v.Elem() - - defaultMu.RLock() - dm, ok := defaults[v.Type()] - defaultMu.RUnlock() - if !ok { - dm = buildDefaultMessage(v.Type()) - defaultMu.Lock() - defaults[v.Type()] = dm - defaultMu.Unlock() - } - - for _, sf := range dm.scalars { - f := v.Field(sf.index) - if !f.IsNil() { - // field already set - continue - } - dv := sf.value - if dv == nil && !zeros { - // no explicit default, and don't want to set zeros - continue - } - fptr := f.Addr().Interface() // **T - // TODO: Consider batching the allocations we do here. - switch sf.kind { - case reflect.Bool: - b := new(bool) - if dv != nil { - *b = dv.(bool) - } - *(fptr.(**bool)) = b - case reflect.Float32: - f := new(float32) - if dv != nil { - *f = dv.(float32) - } - *(fptr.(**float32)) = f - case reflect.Float64: - f := new(float64) - if dv != nil { - *f = dv.(float64) - } - *(fptr.(**float64)) = f - case reflect.Int32: - // might be an enum - if ft := f.Type(); ft != int32PtrType { - // enum - f.Set(reflect.New(ft.Elem())) - if dv != nil { - f.Elem().SetInt(int64(dv.(int32))) - } - } else { - // int32 field - i := new(int32) - if dv != nil { - *i = dv.(int32) - } - *(fptr.(**int32)) = i - } - case reflect.Int64: - i := new(int64) - if dv != nil { - *i = dv.(int64) - } - *(fptr.(**int64)) = i - case reflect.String: - s := new(string) - if dv != nil { - *s = dv.(string) - } - *(fptr.(**string)) = s - case reflect.Uint8: - // exceptional case: []byte - var b []byte - if dv != nil { - db := dv.([]byte) - b = make([]byte, len(db)) - copy(b, db) - } else { - b = []byte{} - } - *(fptr.(*[]byte)) = b - case reflect.Uint32: - u := new(uint32) - if dv != nil { - *u = dv.(uint32) - } - *(fptr.(**uint32)) = u - case reflect.Uint64: - u := new(uint64) - if dv != nil { - *u = dv.(uint64) - } - *(fptr.(**uint64)) = u - default: - log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) - } - } - - for _, ni := range dm.nested { - f := v.Field(ni) - if f.IsNil() { - continue - } - // f is *T or []*T - if f.Kind() == reflect.Ptr { - setDefaults(f, recur, zeros) - } else { - for i := 0; i < f.Len(); i++ { - e := f.Index(i) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - } - } -} - -var ( - // defaults maps a protocol buffer struct type to a slice of the fields, - // with its scalar fields set to their proto-declared non-zero default values. - defaultMu sync.RWMutex - defaults = make(map[reflect.Type]defaultMessage) - - int32PtrType = reflect.TypeOf((*int32)(nil)) -) - -// defaultMessage represents information about the default values of a message. -type defaultMessage struct { - scalars []scalarField - nested []int // struct field index of nested messages -} - -type scalarField struct { - index int // struct field index - kind reflect.Kind // element type (the T in *T or []T) - value interface{} // the proto-declared default value, or nil -} - -func ptrToStruct(t reflect.Type) bool { - return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct -} - -// t is a struct type. -func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { - sprop := GetProperties(t) - for _, prop := range sprop.Prop { - fi, ok := sprop.decoderTags.get(prop.Tag) - if !ok { - // XXX_unrecognized - continue - } - ft := t.Field(fi).Type - - // nested messages - if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) { - dm.nested = append(dm.nested, fi) - continue - } - - sf := scalarField{ - index: fi, - kind: ft.Elem().Kind(), - } - - // scalar fields without defaults - if !prop.HasDefault { - dm.scalars = append(dm.scalars, sf) - continue - } - - // a scalar field: either *T or []byte - switch ft.Elem().Kind() { - case reflect.Bool: - x, err := strconv.ParseBool(prop.Default) - if err != nil { - log.Printf("proto: bad default bool %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.Float32: - x, err := strconv.ParseFloat(prop.Default, 32) - if err != nil { - log.Printf("proto: bad default float32 %q: %v", prop.Default, err) - continue - } - sf.value = float32(x) - case reflect.Float64: - x, err := strconv.ParseFloat(prop.Default, 64) - if err != nil { - log.Printf("proto: bad default float64 %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.Int32: - x, err := strconv.ParseInt(prop.Default, 10, 32) - if err != nil { - log.Printf("proto: bad default int32 %q: %v", prop.Default, err) - continue - } - sf.value = int32(x) - case reflect.Int64: - x, err := strconv.ParseInt(prop.Default, 10, 64) - if err != nil { - log.Printf("proto: bad default int64 %q: %v", prop.Default, err) - continue - } - sf.value = x - case reflect.String: - sf.value = prop.Default - case reflect.Uint8: - // []byte (not *uint8) - sf.value = []byte(prop.Default) - case reflect.Uint32: - x, err := strconv.ParseUint(prop.Default, 10, 32) - if err != nil { - log.Printf("proto: bad default uint32 %q: %v", prop.Default, err) - continue - } - sf.value = uint32(x) - case reflect.Uint64: - x, err := strconv.ParseUint(prop.Default, 10, 64) - if err != nil { - log.Printf("proto: bad default uint64 %q: %v", prop.Default, err) - continue - } - sf.value = x - default: - log.Printf("proto: unhandled def kind %v", ft.Elem().Kind()) - continue - } - - dm.scalars = append(dm.scalars, sf) - } - - return dm -} - -// Map fields may have key types of non-float scalars, strings and enums. -// The easiest way to sort them in some deterministic order is to use fmt. -// If this turns out to be inefficient we can always consider other options, -// such as doing a Schwartzian transform. - -type mapKeys []reflect.Value - -func (s mapKeys) Len() int { return len(s) } -func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s mapKeys) Less(i, j int) bool { - return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface()) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go deleted file mode 100644 index 9d912bce19bb61f69634b9eb8ea64f69f9ddde63..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/message_set.go +++ /dev/null @@ -1,287 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Support for message sets. - */ - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "reflect" - "sort" -) - -// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID. -// A message type ID is required for storing a protocol buffer in a message set. -var ErrNoMessageTypeId = errors.New("proto does not have a message type ID") - -// The first two types (_MessageSet_Item and MessageSet) -// model what the protocol compiler produces for the following protocol message: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } -// That is the MessageSet wire format. We can't use a proto to generate these -// because that would introduce a circular dependency between it and this package. -// -// When a proto1 proto has a field that looks like: -// optional message<MessageSet> info = 3; -// the protocol compiler produces a field in the generated struct that looks like: -// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"` -// The package is automatically inserted so there is no need for that proto file to -// import this package. - -type _MessageSet_Item struct { - TypeId *int32 `protobuf:"varint,2,req,name=type_id"` - Message []byte `protobuf:"bytes,3,req,name=message"` -} - -type MessageSet struct { - Item []*_MessageSet_Item `protobuf:"group,1,rep"` - XXX_unrecognized []byte - // TODO: caching? -} - -// Make sure MessageSet is a Message. -var _ Message = (*MessageSet)(nil) - -// messageTypeIder is an interface satisfied by a protocol buffer type -// that may be stored in a MessageSet. -type messageTypeIder interface { - MessageTypeId() int32 -} - -func (ms *MessageSet) find(pb Message) *_MessageSet_Item { - mti, ok := pb.(messageTypeIder) - if !ok { - return nil - } - id := mti.MessageTypeId() - for _, item := range ms.Item { - if *item.TypeId == id { - return item - } - } - return nil -} - -func (ms *MessageSet) Has(pb Message) bool { - if ms.find(pb) != nil { - return true - } - return false -} - -func (ms *MessageSet) Unmarshal(pb Message) error { - if item := ms.find(pb); item != nil { - return Unmarshal(item.Message, pb) - } - if _, ok := pb.(messageTypeIder); !ok { - return ErrNoMessageTypeId - } - return nil // TODO: return error instead? -} - -func (ms *MessageSet) Marshal(pb Message) error { - msg, err := Marshal(pb) - if err != nil { - return err - } - if item := ms.find(pb); item != nil { - // reuse existing item - item.Message = msg - return nil - } - - mti, ok := pb.(messageTypeIder) - if !ok { - return ErrNoMessageTypeId - } - - mtid := mti.MessageTypeId() - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: &mtid, - Message: msg, - }) - return nil -} - -func (ms *MessageSet) Reset() { *ms = MessageSet{} } -func (ms *MessageSet) String() string { return CompactTextString(ms) } -func (*MessageSet) ProtoMessage() {} - -// Support for the message_set_wire_format message option. - -func skipVarint(buf []byte) []byte { - i := 0 - for ; buf[i]&0x80 != 0; i++ { - } - return buf[i+1:] -} - -// MarshalMessageSet encodes the extension map represented by m in the message set wire format. -// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSet(m map[int32]Extension) ([]byte, error) { - if err := encodeExtensionMap(m); err != nil { - return nil, err - } - - // Sort extension IDs to provide a deterministic encoding. - // See also enc_map in encode.go. - ids := make([]int, 0, len(m)) - for id := range m { - ids = append(ids, int(id)) - } - sort.Ints(ids) - - ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))} - for _, id := range ids { - e := m[int32(id)] - // Remove the wire type and field number varint, as well as the length varint. - msg := skipVarint(skipVarint(e.enc)) - - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: Int32(int32(id)), - Message: msg, - }) - } - return Marshal(ms) -} - -// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error { - ms := new(MessageSet) - if err := Unmarshal(buf, ms); err != nil { - return err - } - for _, item := range ms.Item { - id := *item.TypeId - msg := item.Message - - // Restore wire type and field number varint, plus length varint. - // Be careful to preserve duplicate items. - b := EncodeVarint(uint64(id)<<3 | WireBytes) - if ext, ok := m[id]; ok { - // Existing data; rip off the tag and length varint - // so we join the new data correctly. - // We can assume that ext.enc is set because we are unmarshaling. - o := ext.enc[len(b):] // skip wire type and field number - _, n := DecodeVarint(o) // calculate length of length varint - o = o[n:] // skip length varint - msg = append(o, msg...) // join old data and new data - } - b = append(b, EncodeVarint(uint64(len(msg)))...) - b = append(b, msg...) - - m[id] = Extension{enc: b} - } - return nil -} - -// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. -// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) { - var b bytes.Buffer - b.WriteByte('{') - - // Process the map in key order for deterministic output. - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) // int32Slice defined in text.go - - for i, id := range ids { - ext := m[id] - if i > 0 { - b.WriteByte(',') - } - - msd, ok := messageSetMap[id] - if !ok { - // Unknown type; we can't render it, so skip it. - continue - } - fmt.Fprintf(&b, `"[%s]":`, msd.name) - - x := ext.value - if x == nil { - x = reflect.New(msd.t.Elem()).Interface() - if err := Unmarshal(ext.enc, x.(Message)); err != nil { - return nil, err - } - } - d, err := json.Marshal(x) - if err != nil { - return nil, err - } - b.Write(d) - } - b.WriteByte('}') - return b.Bytes(), nil -} - -// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. -// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. -func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error { - // Common-case fast path. - if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { - return nil - } - - // This is fairly tricky, and it's not clear that it is needed. - return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") -} - -// A global registry of types that can be used in a MessageSet. - -var messageSetMap = make(map[int32]messageSetDesc) - -type messageSetDesc struct { - t reflect.Type // pointer to struct - name string -} - -// RegisterMessageSetType is called from the generated code. -func RegisterMessageSetType(m Message, fieldNum int32, name string) { - messageSetMap[fieldNum] = messageSetDesc{ - t: reflect.TypeOf(m), - name: name, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go deleted file mode 100644 index c68b12525ca0bc6ab4e0000d42e06c4eaa6bb9bd..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_reflect.go +++ /dev/null @@ -1,479 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build appengine - -// This file contains an implementation of proto field accesses using package reflect. -// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can -// be used on App Engine. - -package proto - -import ( - "math" - "reflect" -) - -// A structPointer is a pointer to a struct. -type structPointer struct { - v reflect.Value -} - -// toStructPointer returns a structPointer equivalent to the given reflect value. -// The reflect value must itself be a pointer to a struct. -func toStructPointer(v reflect.Value) structPointer { - return structPointer{v} -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p.v.IsNil() -} - -// Interface returns the struct pointer as an interface value. -func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { - return p.v.Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. -// In this implementation, a field is identified by the sequence of field indices -// passed to reflect's FieldByIndex. -type field []int - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return f.Index -} - -// invalidField is an invalid field identifier. -var invalidField = field(nil) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { return f != nil } - -// field returns the given field in the struct as a reflect value. -func structPointer_field(p structPointer, f field) reflect.Value { - // Special case: an extension map entry with a value of type T - // passes a *T to the struct-handling code with a zero field, - // expecting that it will be treated as equivalent to *struct{ X T }, - // which has the same memory layout. We have to handle that case - // specially, because reflect will panic if we call FieldByIndex on a - // non-struct. - if f == nil { - return p.v.Elem() - } - - return p.v.Elem().FieldByIndex(f) -} - -// ifield returns the given field in the struct as an interface value. -func structPointer_ifield(p structPointer, f field) interface{} { - return structPointer_field(p, f).Addr().Interface() -} - -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return structPointer_ifield(p, f).(*[]byte) -} - -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return structPointer_ifield(p, f).(*[][]byte) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return structPointer_ifield(p, f).(**bool) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return structPointer_ifield(p, f).(*bool) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return structPointer_ifield(p, f).(*[]bool) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return structPointer_ifield(p, f).(**string) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return structPointer_ifield(p, f).(*string) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return structPointer_ifield(p, f).(*[]string) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return structPointer_ifield(p, f).(*map[int32]Extension) -} - -// Map returns the reflect.Value for the address of a map field in the struct. -func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { - return structPointer_field(p, f).Addr() -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - structPointer_field(p, f).Set(q.v) -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return structPointer{structPointer_field(p, f)} -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { - return structPointerSlice{structPointer_field(p, f)} -} - -// A structPointerSlice represents the address of a slice of pointers to structs -// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. -type structPointerSlice struct { - v reflect.Value -} - -func (p structPointerSlice) Len() int { return p.v.Len() } -func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } -func (p structPointerSlice) Append(q structPointer) { - p.v.Set(reflect.Append(p.v, q.v)) -} - -var ( - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - float32Type = reflect.TypeOf(float32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) -) - -// A word32 represents a field of type *int32, *uint32, *float32, or *enum. -// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. -type word32 struct { - v reflect.Value -} - -// IsNil reports whether p is nil. -func word32_IsNil(p word32) bool { - return p.v.IsNil() -} - -// Set sets p to point at a newly allocated word with bits set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - t := p.v.Type().Elem() - switch t { - case int32Type: - if len(o.int32s) == 0 { - o.int32s = make([]int32, uint32PoolSize) - } - o.int32s[0] = int32(x) - p.v.Set(reflect.ValueOf(&o.int32s[0])) - o.int32s = o.int32s[1:] - return - case uint32Type: - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - p.v.Set(reflect.ValueOf(&o.uint32s[0])) - o.uint32s = o.uint32s[1:] - return - case float32Type: - if len(o.float32s) == 0 { - o.float32s = make([]float32, uint32PoolSize) - } - o.float32s[0] = math.Float32frombits(x) - p.v.Set(reflect.ValueOf(&o.float32s[0])) - o.float32s = o.float32s[1:] - return - } - - // must be enum - p.v.Set(reflect.New(t)) - p.v.Elem().SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32_Get(p word32) uint32 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32{structPointer_field(p, f)} -} - -// A word32Val represents a field of type int32, uint32, float32, or enum. -// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. -type word32Val struct { - v reflect.Value -} - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - switch p.v.Type() { - case int32Type: - p.v.SetInt(int64(x)) - return - case uint32Type: - p.v.SetUint(uint64(x)) - return - case float32Type: - p.v.SetFloat(float64(math.Float32frombits(x))) - return - } - - // must be enum - p.v.SetInt(int64(int32(x))) -} - -// Get gets the bits pointed at by p, as a uint32. -func word32Val_Get(p word32Val) uint32 { - elem := p.v - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val{structPointer_field(p, f)} -} - -// A word32Slice is a slice of 32-bit values. -// That is, v.Type() is []int32, []uint32, []float32, or []enum. -type word32Slice struct { - v reflect.Value -} - -func (p word32Slice) Append(x uint32) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int32: - elem.SetInt(int64(int32(x))) - case reflect.Uint32: - elem.SetUint(uint64(x)) - case reflect.Float32: - elem.SetFloat(float64(math.Float32frombits(x))) - } -} - -func (p word32Slice) Len() int { - return p.v.Len() -} - -func (p word32Slice) Index(i int) uint32 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int32: - return uint32(elem.Int()) - case reflect.Uint32: - return uint32(elem.Uint()) - case reflect.Float32: - return math.Float32bits(float32(elem.Float())) - } - panic("unreachable") -} - -// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) word32Slice { - return word32Slice{structPointer_field(p, f)} -} - -// word64 is like word32 but for 64-bit values. -type word64 struct { - v reflect.Value -} - -func word64_Set(p word64, o *Buffer, x uint64) { - t := p.v.Type().Elem() - switch t { - case int64Type: - if len(o.int64s) == 0 { - o.int64s = make([]int64, uint64PoolSize) - } - o.int64s[0] = int64(x) - p.v.Set(reflect.ValueOf(&o.int64s[0])) - o.int64s = o.int64s[1:] - return - case uint64Type: - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - p.v.Set(reflect.ValueOf(&o.uint64s[0])) - o.uint64s = o.uint64s[1:] - return - case float64Type: - if len(o.float64s) == 0 { - o.float64s = make([]float64, uint64PoolSize) - } - o.float64s[0] = math.Float64frombits(x) - p.v.Set(reflect.ValueOf(&o.float64s[0])) - o.float64s = o.float64s[1:] - return - } - panic("unreachable") -} - -func word64_IsNil(p word64) bool { - return p.v.IsNil() -} - -func word64_Get(p word64) uint64 { - elem := p.v.Elem() - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) - } - panic("unreachable") -} - -func structPointer_Word64(p structPointer, f field) word64 { - return word64{structPointer_field(p, f)} -} - -// word64Val is like word32Val but for 64-bit values. -type word64Val struct { - v reflect.Value -} - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - switch p.v.Type() { - case int64Type: - p.v.SetInt(int64(x)) - return - case uint64Type: - p.v.SetUint(x) - return - case float64Type: - p.v.SetFloat(math.Float64frombits(x)) - return - } - panic("unreachable") -} - -func word64Val_Get(p word64Val) uint64 { - elem := p.v - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return elem.Uint() - case reflect.Float64: - return math.Float64bits(elem.Float()) - } - panic("unreachable") -} - -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val{structPointer_field(p, f)} -} - -type word64Slice struct { - v reflect.Value -} - -func (p word64Slice) Append(x uint64) { - n, m := p.v.Len(), p.v.Cap() - if n < m { - p.v.SetLen(n + 1) - } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) - } - elem := p.v.Index(n) - switch elem.Kind() { - case reflect.Int64: - elem.SetInt(int64(int64(x))) - case reflect.Uint64: - elem.SetUint(uint64(x)) - case reflect.Float64: - elem.SetFloat(float64(math.Float64frombits(x))) - } -} - -func (p word64Slice) Len() int { - return p.v.Len() -} - -func (p word64Slice) Index(i int) uint64 { - elem := p.v.Index(i) - switch elem.Kind() { - case reflect.Int64: - return uint64(elem.Int()) - case reflect.Uint64: - return uint64(elem.Uint()) - case reflect.Float64: - return math.Float64bits(float64(elem.Float())) - } - panic("unreachable") -} - -func structPointer_Word64Slice(p structPointer, f field) word64Slice { - return word64Slice{structPointer_field(p, f)} -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go deleted file mode 100644 index 48bc0fa48278473461b9cef804dd159d9483308e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/pointer_unsafe.go +++ /dev/null @@ -1,266 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build !appengine - -// This file contains the implementation of the proto field accesses using package unsafe. - -package proto - -import ( - "reflect" - "unsafe" -) - -// NOTE: These type_Foo functions would more idiomatically be methods, -// but Go does not allow methods on pointer types, and we must preserve -// some pointer type for the garbage collector. We use these -// funcs with clunky names as our poor approximation to methods. -// -// An alternative would be -// type structPointer struct { p unsafe.Pointer } -// but that does not registerize as well. - -// A structPointer is a pointer to a struct. -type structPointer unsafe.Pointer - -// toStructPointer returns a structPointer equivalent to the given reflect value. -func toStructPointer(v reflect.Value) structPointer { - return structPointer(unsafe.Pointer(v.Pointer())) -} - -// IsNil reports whether p is nil. -func structPointer_IsNil(p structPointer) bool { - return p == nil -} - -// Interface returns the struct pointer, assumed to have element type t, -// as an interface value. -func structPointer_Interface(p structPointer, t reflect.Type) interface{} { - return reflect.NewAt(t, unsafe.Pointer(p)).Interface() -} - -// A field identifies a field in a struct, accessible from a structPointer. -// In this implementation, a field is identified by its byte offset from the start of the struct. -type field uintptr - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return field(f.Offset) -} - -// invalidField is an invalid field identifier. -const invalidField = ^field(0) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { - return f != ^field(0) -} - -// Bytes returns the address of a []byte field in the struct. -func structPointer_Bytes(p structPointer, f field) *[]byte { - return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BytesSlice returns the address of a [][]byte field in the struct. -func structPointer_BytesSlice(p structPointer, f field) *[][]byte { - return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// Bool returns the address of a *bool field in the struct. -func structPointer_Bool(p structPointer, f field) **bool { - return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolVal returns the address of a bool field in the struct. -func structPointer_BoolVal(p structPointer, f field) *bool { - return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// BoolSlice returns the address of a []bool field in the struct. -func structPointer_BoolSlice(p structPointer, f field) *[]bool { - return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// String returns the address of a *string field in the struct. -func structPointer_String(p structPointer, f field) **string { - return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringVal returns the address of a string field in the struct. -func structPointer_StringVal(p structPointer, f field) *string { - return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StringSlice returns the address of a []string field in the struct. -func structPointer_StringSlice(p structPointer, f field) *[]string { - return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// ExtMap returns the address of an extension map field in the struct. -func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { - return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// Map returns the reflect.Value for the address of a map field in the struct. -func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value { - return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) -} - -// SetStructPointer writes a *struct field in the struct. -func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { - *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q -} - -// GetStructPointer reads a *struct field in the struct. -func structPointer_GetStructPointer(p structPointer, f field) structPointer { - return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// StructPointerSlice the address of a []*struct field in the struct. -func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { - return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). -type structPointerSlice []structPointer - -func (v *structPointerSlice) Len() int { return len(*v) } -func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } -func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } - -// A word32 is the address of a "pointer to 32-bit value" field. -type word32 **uint32 - -// IsNil reports whether *v is nil. -func word32_IsNil(p word32) bool { - return *p == nil -} - -// Set sets *v to point at a newly allocated word set to x. -func word32_Set(p word32, o *Buffer, x uint32) { - if len(o.uint32s) == 0 { - o.uint32s = make([]uint32, uint32PoolSize) - } - o.uint32s[0] = x - *p = &o.uint32s[0] - o.uint32s = o.uint32s[1:] -} - -// Get gets the value pointed at by *v. -func word32_Get(p word32) uint32 { - return **p -} - -// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32(p structPointer, f field) word32 { - return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Val is the address of a 32-bit value field. -type word32Val *uint32 - -// Set sets *p to x. -func word32Val_Set(p word32Val, x uint32) { - *p = x -} - -// Get gets the value pointed at by p. -func word32Val_Get(p word32Val) uint32 { - return *p -} - -// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. -func structPointer_Word32Val(p structPointer, f field) word32Val { - return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// A word32Slice is a slice of 32-bit values. -type word32Slice []uint32 - -func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } -func (v *word32Slice) Len() int { return len(*v) } -func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } - -// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. -func structPointer_Word32Slice(p structPointer, f field) *word32Slice { - return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} - -// word64 is like word32 but for 64-bit values. -type word64 **uint64 - -func word64_Set(p word64, o *Buffer, x uint64) { - if len(o.uint64s) == 0 { - o.uint64s = make([]uint64, uint64PoolSize) - } - o.uint64s[0] = x - *p = &o.uint64s[0] - o.uint64s = o.uint64s[1:] -} - -func word64_IsNil(p word64) bool { - return *p == nil -} - -func word64_Get(p word64) uint64 { - return **p -} - -func structPointer_Word64(p structPointer, f field) word64 { - return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// word64Val is like word32Val but for 64-bit values. -type word64Val *uint64 - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - *p = x -} - -func word64Val_Get(p word64Val) uint64 { - return *p -} - -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) -} - -// word64Slice is like word32Slice but for 64-bit values. -type word64Slice []uint64 - -func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } -func (v *word64Slice) Len() int { return len(*v) } -func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } - -func structPointer_Word64Slice(p structPointer, f field) *word64Slice { - return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go deleted file mode 100644 index 7216544815559344b2efe7cf60bf4484d9fbae42..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/properties.go +++ /dev/null @@ -1,737 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "fmt" - "os" - "reflect" - "sort" - "strconv" - "strings" - "sync" -) - -const debug bool = false - -// Constants that identify the encoding of a value on the wire. -const ( - WireVarint = 0 - WireFixed64 = 1 - WireBytes = 2 - WireStartGroup = 3 - WireEndGroup = 4 - WireFixed32 = 5 -) - -const startSize = 10 // initial slice/string sizes - -// Encoders are defined in encode.go -// An encoder outputs the full representation of a field, including its -// tag and encoder type. -type encoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueEncoder encodes a single integer in a particular encoding. -type valueEncoder func(o *Buffer, x uint64) error - -// Sizers are defined in encode.go -// A sizer returns the encoded size of a field, including its tag and encoder -// type. -type sizer func(prop *Properties, base structPointer) int - -// A valueSizer returns the encoded size of a single integer in a particular -// encoding. -type valueSizer func(x uint64) int - -// Decoders are defined in decode.go -// A decoder creates a value from its wire representation. -// Unrecognized subelements are saved in unrec. -type decoder func(p *Buffer, prop *Properties, base structPointer) error - -// A valueDecoder decodes a single integer in a particular encoding. -type valueDecoder func(o *Buffer) (x uint64, err error) - -// tagMap is an optimization over map[int]int for typical protocol buffer -// use-cases. Encoded protocol buffers are often in tag order with small tag -// numbers. -type tagMap struct { - fastTags []int - slowTags map[int]int -} - -// tagMapFastLimit is the upper bound on the tag number that will be stored in -// the tagMap slice rather than its map. -const tagMapFastLimit = 1024 - -func (p *tagMap) get(t int) (int, bool) { - if t > 0 && t < tagMapFastLimit { - if t >= len(p.fastTags) { - return 0, false - } - fi := p.fastTags[t] - return fi, fi >= 0 - } - fi, ok := p.slowTags[t] - return fi, ok -} - -func (p *tagMap) put(t int, fi int) { - if t > 0 && t < tagMapFastLimit { - for len(p.fastTags) < t+1 { - p.fastTags = append(p.fastTags, -1) - } - p.fastTags[t] = fi - return - } - if p.slowTags == nil { - p.slowTags = make(map[int]int) - } - p.slowTags[t] = fi -} - -// StructProperties represents properties for all the fields of a struct. -// decoderTags and decoderOrigNames should only be used by the decoder. -type StructProperties struct { - Prop []*Properties // properties for each field - reqCount int // required count - decoderTags tagMap // map from proto tag to struct field number - decoderOrigNames map[string]int // map from original name to struct field number - order []int // list of struct field numbers in tag order - unrecField field // field id of the XXX_unrecognized []byte field - extendable bool // is this an extendable proto -} - -// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. -// See encode.go, (*Buffer).enc_struct. - -func (sp *StructProperties) Len() int { return len(sp.order) } -func (sp *StructProperties) Less(i, j int) bool { - return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag -} -func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } - -// Properties represents the protocol-specific behavior of a single struct field. -type Properties struct { - Name string // name of the field, for error messages - OrigName string // original name before protocol compiler (always set) - Wire string - WireType int - Tag int - Required bool - Optional bool - Repeated bool - Packed bool // relevant for repeated primitives only - Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field; set for []byte only - - Default string // default value - HasDefault bool // whether an explicit default was provided - def_uint64 uint64 - - enc encoder - valEnc valueEncoder // set for bool and numeric types only - field field - tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) - tagbuf [8]byte - stype reflect.Type // set for struct types only - sprop *StructProperties // set for struct types only - isMarshaler bool - isUnmarshaler bool - - mtype reflect.Type // set for map types only - mkeyprop *Properties // set for map types only - mvalprop *Properties // set for map types only - - size sizer - valSize valueSizer // set for bool and numeric types only - - dec decoder - valDec valueDecoder // set for bool and numeric types only - - // If this is a packable field, this will be the decoder for the packed version of the field. - packedDec decoder -} - -// String formats the properties in the protobuf struct field tag style. -func (p *Properties) String() string { - s := p.Wire - s = "," - s += strconv.Itoa(p.Tag) - if p.Required { - s += ",req" - } - if p.Optional { - s += ",opt" - } - if p.Repeated { - s += ",rep" - } - if p.Packed { - s += ",packed" - } - if p.OrigName != p.Name { - s += ",name=" + p.OrigName - } - if p.proto3 { - s += ",proto3" - } - if len(p.Enum) > 0 { - s += ",enum=" + p.Enum - } - if p.HasDefault { - s += ",def=" + p.Default - } - return s -} - -// Parse populates p by parsing a string in the protobuf struct field tag style. -func (p *Properties) Parse(s string) { - // "bytes,49,opt,name=foo,def=hello!" - fields := strings.Split(s, ",") // breaks def=, but handled below. - if len(fields) < 2 { - fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) - return - } - - p.Wire = fields[0] - switch p.Wire { - case "varint": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeVarint - p.valDec = (*Buffer).DecodeVarint - p.valSize = sizeVarint - case "fixed32": - p.WireType = WireFixed32 - p.valEnc = (*Buffer).EncodeFixed32 - p.valDec = (*Buffer).DecodeFixed32 - p.valSize = sizeFixed32 - case "fixed64": - p.WireType = WireFixed64 - p.valEnc = (*Buffer).EncodeFixed64 - p.valDec = (*Buffer).DecodeFixed64 - p.valSize = sizeFixed64 - case "zigzag32": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag32 - p.valDec = (*Buffer).DecodeZigzag32 - p.valSize = sizeZigzag32 - case "zigzag64": - p.WireType = WireVarint - p.valEnc = (*Buffer).EncodeZigzag64 - p.valDec = (*Buffer).DecodeZigzag64 - p.valSize = sizeZigzag64 - case "bytes", "group": - p.WireType = WireBytes - // no numeric converter for non-numeric types - default: - fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) - return - } - - var err error - p.Tag, err = strconv.Atoi(fields[1]) - if err != nil { - return - } - - for i := 2; i < len(fields); i++ { - f := fields[i] - switch { - case f == "req": - p.Required = true - case f == "opt": - p.Optional = true - case f == "rep": - p.Repeated = true - case f == "packed": - p.Packed = true - case strings.HasPrefix(f, "name="): - p.OrigName = f[5:] - case strings.HasPrefix(f, "enum="): - p.Enum = f[5:] - case f == "proto3": - p.proto3 = true - case strings.HasPrefix(f, "def="): - p.HasDefault = true - p.Default = f[4:] // rest of string - if i+1 < len(fields) { - // Commas aren't escaped, and def is always last. - p.Default += "," + strings.Join(fields[i+1:], ",") - break - } - } - } -} - -func logNoSliceEnc(t1, t2 reflect.Type) { - fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) -} - -var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() - -// Initialize the fields for encoding and decoding. -func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - p.enc = nil - p.dec = nil - p.size = nil - - switch t1 := typ; t1.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) - - // proto3 scalar types - - case reflect.Bool: - p.enc = (*Buffer).enc_proto3_bool - p.dec = (*Buffer).dec_proto3_bool - p.size = size_proto3_bool - case reflect.Int32: - p.enc = (*Buffer).enc_proto3_int32 - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_proto3_uint32 - p.dec = (*Buffer).dec_proto3_int32 // can reuse - p.size = size_proto3_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_proto3_int64 - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.String: - p.enc = (*Buffer).enc_proto3_string - p.dec = (*Buffer).dec_proto3_string - p.size = size_proto3_string - - case reflect.Ptr: - switch t2 := t1.Elem(); t2.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) - break - case reflect.Bool: - p.enc = (*Buffer).enc_bool - p.dec = (*Buffer).dec_bool - p.size = size_bool - case reflect.Int32: - p.enc = (*Buffer).enc_int32 - p.dec = (*Buffer).dec_int32 - p.size = size_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_uint32 - p.dec = (*Buffer).dec_int32 // can reuse - p.size = size_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_int64 - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_int32 - p.size = size_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_int64 // can just treat them as bits - p.dec = (*Buffer).dec_int64 - p.size = size_int64 - case reflect.String: - p.enc = (*Buffer).enc_string - p.dec = (*Buffer).dec_string - p.size = size_string - case reflect.Struct: - p.stype = t1.Elem() - p.isMarshaler = isMarshaler(t1) - p.isUnmarshaler = isUnmarshaler(t1) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_struct_message - p.dec = (*Buffer).dec_struct_message - p.size = size_struct_message - } else { - p.enc = (*Buffer).enc_struct_group - p.dec = (*Buffer).dec_struct_group - p.size = size_struct_group - } - } - - case reflect.Slice: - switch t2 := t1.Elem(); t2.Kind() { - default: - logNoSliceEnc(t1, t2) - break - case reflect.Bool: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_bool - p.size = size_slice_packed_bool - } else { - p.enc = (*Buffer).enc_slice_bool - p.size = size_slice_bool - } - p.dec = (*Buffer).dec_slice_bool - p.packedDec = (*Buffer).dec_slice_packed_bool - case reflect.Int32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int32 - p.size = size_slice_packed_int32 - } else { - p.enc = (*Buffer).enc_slice_int32 - p.size = size_slice_int32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Uint32: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case reflect.Int64, reflect.Uint64: - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - case reflect.Uint8: - p.enc = (*Buffer).enc_slice_byte - p.dec = (*Buffer).dec_slice_byte - p.size = size_slice_byte - if p.proto3 { - p.enc = (*Buffer).enc_proto3_slice_byte - p.size = size_proto3_slice_byte - } - case reflect.Float32, reflect.Float64: - switch t2.Bits() { - case 32: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_uint32 - p.size = size_slice_packed_uint32 - } else { - p.enc = (*Buffer).enc_slice_uint32 - p.size = size_slice_uint32 - } - p.dec = (*Buffer).dec_slice_int32 - p.packedDec = (*Buffer).dec_slice_packed_int32 - case 64: - // can just treat them as bits - if p.Packed { - p.enc = (*Buffer).enc_slice_packed_int64 - p.size = size_slice_packed_int64 - } else { - p.enc = (*Buffer).enc_slice_int64 - p.size = size_slice_int64 - } - p.dec = (*Buffer).dec_slice_int64 - p.packedDec = (*Buffer).dec_slice_packed_int64 - default: - logNoSliceEnc(t1, t2) - break - } - case reflect.String: - p.enc = (*Buffer).enc_slice_string - p.dec = (*Buffer).dec_slice_string - p.size = size_slice_string - case reflect.Ptr: - switch t3 := t2.Elem(); t3.Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) - break - case reflect.Struct: - p.stype = t2.Elem() - p.isMarshaler = isMarshaler(t2) - p.isUnmarshaler = isUnmarshaler(t2) - if p.Wire == "bytes" { - p.enc = (*Buffer).enc_slice_struct_message - p.dec = (*Buffer).dec_slice_struct_message - p.size = size_slice_struct_message - } else { - p.enc = (*Buffer).enc_slice_struct_group - p.dec = (*Buffer).dec_slice_struct_group - p.size = size_slice_struct_group - } - } - case reflect.Slice: - switch t2.Elem().Kind() { - default: - fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) - break - case reflect.Uint8: - p.enc = (*Buffer).enc_slice_slice_byte - p.dec = (*Buffer).dec_slice_slice_byte - p.size = size_slice_slice_byte - } - } - - case reflect.Map: - p.enc = (*Buffer).enc_new_map - p.dec = (*Buffer).dec_new_map - p.size = size_new_map - - p.mtype = t1 - p.mkeyprop = &Properties{} - p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.mvalprop = &Properties{} - vtype := p.mtype.Elem() - if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { - // The value type is not a message (*T) or bytes ([]byte), - // so we need encoders for the pointer to this type. - vtype = reflect.PtrTo(vtype) - } - p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) - } - - // precalculate tag code - wire := p.WireType - if p.Packed { - wire = WireBytes - } - x := uint32(p.Tag)<<3 | uint32(wire) - i := 0 - for i = 0; x > 127; i++ { - p.tagbuf[i] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - p.tagbuf[i] = uint8(x) - p.tagcode = p.tagbuf[0 : i+1] - - if p.stype != nil { - if lockGetProp { - p.sprop = GetProperties(p.stype) - } else { - p.sprop = getPropertiesLocked(p.stype) - } - } -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() -) - -// isMarshaler reports whether type t implements Marshaler. -func isMarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isMarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isMarshaler") - } - return t.Implements(marshalerType) -} - -// isUnmarshaler reports whether type t implements Unmarshaler. -func isUnmarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isUnmarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isUnmarshaler") - } - return t.Implements(unmarshalerType) -} - -// Init populates the properties from a protocol buffer struct tag. -func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { - p.init(typ, name, tag, f, true) -} - -func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { - // "bytes,49,opt,def=hello!" - p.Name = name - p.OrigName = name - if f != nil { - p.field = toField(f) - } - if tag == "" { - return - } - p.Parse(tag) - p.setEncAndDec(typ, f, lockGetProp) -} - -var ( - propertiesMu sync.RWMutex - propertiesMap = make(map[reflect.Type]*StructProperties) -) - -// GetProperties returns the list of properties for the type represented by t. -// t must represent a generated struct type of a protocol message. -func GetProperties(t reflect.Type) *StructProperties { - if t.Kind() != reflect.Struct { - panic("proto: type must have kind struct") - } - - // Most calls to GetProperties in a long-running program will be - // retrieving details for types we have seen before. - propertiesMu.RLock() - sprop, ok := propertiesMap[t] - propertiesMu.RUnlock() - if ok { - if collectStats { - stats.Chit++ - } - return sprop - } - - propertiesMu.Lock() - sprop = getPropertiesLocked(t) - propertiesMu.Unlock() - return sprop -} - -// getPropertiesLocked requires that propertiesMu is held. -func getPropertiesLocked(t reflect.Type) *StructProperties { - if prop, ok := propertiesMap[t]; ok { - if collectStats { - stats.Chit++ - } - return prop - } - if collectStats { - stats.Cmiss++ - } - - prop := new(StructProperties) - // in case of recursive protos, fill this in now. - propertiesMap[t] = prop - - // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) - prop.unrecField = invalidField - prop.Prop = make([]*Properties, t.NumField()) - prop.order = make([]int, t.NumField()) - - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - p := new(Properties) - name := f.Name - p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - - if f.Name == "XXX_extensions" { // special case - p.enc = (*Buffer).enc_map - p.dec = nil // not needed - p.size = size_map - } - if f.Name == "XXX_unrecognized" { // special case - prop.unrecField = toField(&f) - } - prop.Prop[i] = p - prop.order[i] = i - if debug { - print(i, " ", f.Name, " ", t.String(), " ") - if p.Tag > 0 { - print(p.String()) - } - print("\n") - } - if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") { - fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") - } - } - - // Re-order prop.order. - sort.Sort(prop) - - // build required counts - // build tags - reqCount := 0 - prop.decoderOrigNames = make(map[string]int) - for i, p := range prop.Prop { - if strings.HasPrefix(p.Name, "XXX_") { - // Internal fields should not appear in tags/origNames maps. - // They are handled specially when encoding and decoding. - continue - } - if p.Required { - reqCount++ - } - prop.decoderTags.put(p.Tag, i) - prop.decoderOrigNames[p.OrigName] = i - } - prop.reqCount = reqCount - - return prop -} - -// Return the Properties object for the x[0]'th field of the structure. -func propByIndex(t reflect.Type, x []int) *Properties { - if len(x) != 1 { - fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) - return nil - } - prop := GetProperties(t) - return prop.Prop[x[0]] -} - -// Get the address and type of a pointer to a struct from an interface. -func getbase(pb Message) (t reflect.Type, b structPointer, err error) { - if pb == nil { - err = ErrNil - return - } - // get the reflect type of the pointer to the struct. - t = reflect.TypeOf(pb) - // get the address of the struct. - value := reflect.ValueOf(pb) - b = toStructPointer(value) - return -} - -// A global registry of enum types. -// The generated code will register the generated maps by calling RegisterEnum. - -var enumValueMaps = make(map[string]map[string]int32) - -// RegisterEnum is called from the generated code to install the enum descriptor -// maps into the global table to aid parsing text format protocol buffers. -func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { - if _, ok := enumValueMaps[typeName]; ok { - panic("proto: duplicate enum registered: " + typeName) - } - enumValueMaps[typeName] = valueMap -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go deleted file mode 100644 index 720eac470505075186dfdc2701834171012486c6..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text.go +++ /dev/null @@ -1,789 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for writing the text protocol buffer format. - -import ( - "bufio" - "bytes" - "encoding" - "fmt" - "io" - "log" - "math" - "os" - "reflect" - "sort" - "strings" -) - -var ( - newline = []byte("\n") - spaces = []byte(" ") - gtNewline = []byte(">\n") - endBraceNewline = []byte("}\n") - backslashN = []byte{'\\', 'n'} - backslashR = []byte{'\\', 'r'} - backslashT = []byte{'\\', 't'} - backslashDQ = []byte{'\\', '"'} - backslashBS = []byte{'\\', '\\'} - posInf = []byte("inf") - negInf = []byte("-inf") - nan = []byte("nan") -) - -type writer interface { - io.Writer - WriteByte(byte) error -} - -// textWriter is an io.Writer that tracks its indentation level. -type textWriter struct { - ind int - complete bool // if the current position is a complete line - compact bool // whether to write out as a one-liner - w writer -} - -func (w *textWriter) WriteString(s string) (n int, err error) { - if !strings.Contains(s, "\n") { - if !w.compact && w.complete { - w.writeIndent() - } - w.complete = false - return io.WriteString(w.w, s) - } - // WriteString is typically called without newlines, so this - // codepath and its copy are rare. We copy to avoid - // duplicating all of Write's logic here. - return w.Write([]byte(s)) -} - -func (w *textWriter) Write(p []byte) (n int, err error) { - newlines := bytes.Count(p, newline) - if newlines == 0 { - if !w.compact && w.complete { - w.writeIndent() - } - n, err = w.w.Write(p) - w.complete = false - return n, err - } - - frags := bytes.SplitN(p, newline, newlines+1) - if w.compact { - for i, frag := range frags { - if i > 0 { - if err := w.w.WriteByte(' '); err != nil { - return n, err - } - n++ - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - } - return n, nil - } - - for i, frag := range frags { - if w.complete { - w.writeIndent() - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - if i+1 < len(frags) { - if err := w.w.WriteByte('\n'); err != nil { - return n, err - } - n++ - } - } - w.complete = len(frags[len(frags)-1]) == 0 - return n, nil -} - -func (w *textWriter) WriteByte(c byte) error { - if w.compact && c == '\n' { - c = ' ' - } - if !w.compact && w.complete { - w.writeIndent() - } - err := w.w.WriteByte(c) - w.complete = c == '\n' - return err -} - -func (w *textWriter) indent() { w.ind++ } - -func (w *textWriter) unindent() { - if w.ind == 0 { - log.Printf("proto: textWriter unindented too far") - return - } - w.ind-- -} - -func writeName(w *textWriter, props *Properties) error { - if _, err := w.WriteString(props.OrigName); err != nil { - return err - } - if props.Wire != "group" { - return w.WriteByte(':') - } - return nil -} - -var ( - messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem() -) - -// raw is the interface satisfied by RawMessage. -type raw interface { - Bytes() []byte -} - -func writeStruct(w *textWriter, sv reflect.Value) error { - if sv.Type() == messageSetType { - return writeMessageSet(w, sv.Addr().Interface().(*MessageSet)) - } - - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < sv.NumField(); i++ { - fv := sv.Field(i) - props := sprops.Prop[i] - name := st.Field(i).Name - - if strings.HasPrefix(name, "XXX_") { - // There are two XXX_ fields: - // XXX_unrecognized []byte - // XXX_extensions map[int32]proto.Extension - // The first is handled here; - // the second is handled at the bottom of this function. - if name == "XXX_unrecognized" && !fv.IsNil() { - if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Field not filled in. This could be an optional field or - // a required field that wasn't filled in. Either way, there - // isn't anything we can show for it. - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - // Repeated field that is empty, or a bytes field that is unused. - continue - } - - if props.Repeated && fv.Kind() == reflect.Slice { - // Repeated field. - for j := 0; j < fv.Len(); j++ { - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - v := fv.Index(j) - if v.Kind() == reflect.Ptr && v.IsNil() { - // A nil message in a repeated field is not valid, - // but we can handle that more gracefully than panicking. - if _, err := w.Write([]byte("<nil>\n")); err != nil { - return err - } - continue - } - if err := writeAny(w, v, props); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Map { - // Map fields are rendered as a repeated struct with key/value fields. - keys := fv.MapKeys() // TODO: should we sort these for deterministic output? - sort.Sort(mapKeys(keys)) - for _, key := range keys { - val := fv.MapIndex(key) - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - // open struct - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - // key - if _, err := w.WriteString("key:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := writeAny(w, key, props.mkeyprop); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - // value - if _, err := w.WriteString("value:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := writeAny(w, val, props.mvalprop); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - // close struct - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { - // empty bytes field - continue - } - if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { - // proto3 non-repeated scalar field; skip if zero value - switch fv.Kind() { - case reflect.Bool: - if !fv.Bool() { - continue - } - case reflect.Int32, reflect.Int64: - if fv.Int() == 0 { - continue - } - case reflect.Uint32, reflect.Uint64: - if fv.Uint() == 0 { - continue - } - case reflect.Float32, reflect.Float64: - if fv.Float() == 0 { - continue - } - case reflect.String: - if fv.String() == "" { - continue - } - } - } - - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if b, ok := fv.Interface().(raw); ok { - if err := writeRaw(w, b.Bytes()); err != nil { - return err - } - continue - } - - // Enums have a String method, so writeAny will work fine. - if err := writeAny(w, fv, props); err != nil { - return err - } - - if err := w.WriteByte('\n'); err != nil { - return err - } - } - - // Extensions (the XXX_extensions field). - pv := sv.Addr() - if pv.Type().Implements(extendableProtoType) { - if err := writeExtensions(w, pv); err != nil { - return err - } - } - - return nil -} - -// writeRaw writes an uninterpreted raw message. -func writeRaw(w *textWriter, b []byte) error { - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if err := writeUnknownStruct(w, b); err != nil { - return err - } - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - return nil -} - -// writeAny writes an arbitrary field. -func writeAny(w *textWriter, v reflect.Value, props *Properties) error { - v = reflect.Indirect(v) - - // Floats have special cases. - if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { - x := v.Float() - var b []byte - switch { - case math.IsInf(x, 1): - b = posInf - case math.IsInf(x, -1): - b = negInf - case math.IsNaN(x): - b = nan - } - if b != nil { - _, err := w.Write(b) - return err - } - // Other values are handled below. - } - - // We don't attempt to serialise every possible value type; only those - // that can occur in protocol buffers. - switch v.Kind() { - case reflect.Slice: - // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Interface().([]byte))); err != nil { - return err - } - case reflect.String: - if err := writeString(w, v.String()); err != nil { - return err - } - case reflect.Struct: - // Required/optional group/message. - var bra, ket byte = '<', '>' - if props != nil && props.Wire == "group" { - bra, ket = '{', '}' - } - if err := w.WriteByte(bra); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if tm, ok := v.Interface().(encoding.TextMarshaler); ok { - text, err := tm.MarshalText() - if err != nil { - return err - } - if _, err = w.Write(text); err != nil { - return err - } - } else if err := writeStruct(w, v); err != nil { - return err - } - w.unindent() - if err := w.WriteByte(ket); err != nil { - return err - } - default: - _, err := fmt.Fprint(w, v.Interface()) - return err - } - return nil -} - -// equivalent to C's isprint. -func isprint(c byte) bool { - return c >= 0x20 && c < 0x7f -} - -// writeString writes a string in the protocol buffer text format. -// It is similar to strconv.Quote except we don't use Go escape sequences, -// we treat the string as a byte sequence, and we use octal escapes. -// These differences are to maintain interoperability with the other -// languages' implementations of the text format. -func writeString(w *textWriter, s string) error { - // use WriteByte here to get any needed indent - if err := w.WriteByte('"'); err != nil { - return err - } - // Loop over the bytes, not the runes. - for i := 0; i < len(s); i++ { - var err error - // Divergence from C++: we don't escape apostrophes. - // There's no need to escape them, and the C++ parser - // copes with a naked apostrophe. - switch c := s[i]; c { - case '\n': - _, err = w.w.Write(backslashN) - case '\r': - _, err = w.w.Write(backslashR) - case '\t': - _, err = w.w.Write(backslashT) - case '"': - _, err = w.w.Write(backslashDQ) - case '\\': - _, err = w.w.Write(backslashBS) - default: - if isprint(c) { - err = w.w.WriteByte(c) - } else { - _, err = fmt.Fprintf(w.w, "\\%03o", c) - } - } - if err != nil { - return err - } - } - return w.WriteByte('"') -} - -func writeMessageSet(w *textWriter, ms *MessageSet) error { - for _, item := range ms.Item { - id := *item.TypeId - if msd, ok := messageSetMap[id]; ok { - // Known message set type. - if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil { - return err - } - w.indent() - - pb := reflect.New(msd.t.Elem()) - if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil { - if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil { - return err - } - } else { - if err := writeStruct(w, pb.Elem()); err != nil { - return err - } - } - } else { - // Unknown type. - if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil { - return err - } - w.indent() - if err := writeUnknownStruct(w, item.Message); err != nil { - return err - } - } - w.unindent() - if _, err := w.Write(gtNewline); err != nil { - return err - } - } - return nil -} - -func writeUnknownStruct(w *textWriter, data []byte) (err error) { - if !w.compact { - if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { - return err - } - } - b := NewBuffer(data) - for b.index < len(b.buf) { - x, err := b.DecodeVarint() - if err != nil { - _, err := fmt.Fprintf(w, "/* %v */\n", err) - return err - } - wire, tag := x&7, x>>3 - if wire == WireEndGroup { - w.unindent() - if _, err := w.Write(endBraceNewline); err != nil { - return err - } - continue - } - if _, err := fmt.Fprint(w, tag); err != nil { - return err - } - if wire != WireStartGroup { - if err := w.WriteByte(':'); err != nil { - return err - } - } - if !w.compact || wire == WireStartGroup { - if err := w.WriteByte(' '); err != nil { - return err - } - } - switch wire { - case WireBytes: - buf, e := b.DecodeRawBytes(false) - if e == nil { - _, err = fmt.Fprintf(w, "%q", buf) - } else { - _, err = fmt.Fprintf(w, "/* %v */", e) - } - case WireFixed32: - x, err = b.DecodeFixed32() - err = writeUnknownInt(w, x, err) - case WireFixed64: - x, err = b.DecodeFixed64() - err = writeUnknownInt(w, x, err) - case WireStartGroup: - err = w.WriteByte('{') - w.indent() - case WireVarint: - x, err = b.DecodeVarint() - err = writeUnknownInt(w, x, err) - default: - _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) - } - if err != nil { - return err - } - if err = w.WriteByte('\n'); err != nil { - return err - } - } - return nil -} - -func writeUnknownInt(w *textWriter, x uint64, err error) error { - if err == nil { - _, err = fmt.Fprint(w, x) - } else { - _, err = fmt.Fprintf(w, "/* %v */", err) - } - return err -} - -type int32Slice []int32 - -func (s int32Slice) Len() int { return len(s) } -func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } -func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// writeExtensions writes all the extensions in pv. -// pv is assumed to be a pointer to a protocol message struct that is extendable. -func writeExtensions(w *textWriter, pv reflect.Value) error { - emap := extensionMaps[pv.Type().Elem()] - ep := pv.Interface().(extendableProto) - - // Order the extensions by ID. - // This isn't strictly necessary, but it will give us - // canonical output, which will also make testing easier. - m := ep.ExtensionMap() - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) - - for _, extNum := range ids { - ext := m[extNum] - var desc *ExtensionDesc - if emap != nil { - desc = emap[extNum] - } - if desc == nil { - // Unknown extension. - if err := writeUnknownStruct(w, ext.enc); err != nil { - return err - } - continue - } - - pb, err := GetExtension(ep, desc) - if err != nil { - if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil { - return err - } - continue - } - - // Repeated extensions will appear as a slice. - if !desc.repeated() { - if err := writeExtension(w, desc.Name, pb); err != nil { - return err - } - } else { - v := reflect.ValueOf(pb) - for i := 0; i < v.Len(); i++ { - if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { - return err - } - } - } - } - return nil -} - -func writeExtension(w *textWriter, name string, pb interface{}) error { - if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - return nil -} - -func (w *textWriter) writeIndent() { - if !w.complete { - return - } - remain := w.ind * 2 - for remain > 0 { - n := remain - if n > len(spaces) { - n = len(spaces) - } - w.w.Write(spaces[:n]) - remain -= n - } - w.complete = false -} - -func marshalText(w io.Writer, pb Message, compact bool) error { - val := reflect.ValueOf(pb) - if pb == nil || val.IsNil() { - w.Write([]byte("<nil>")) - return nil - } - var bw *bufio.Writer - ww, ok := w.(writer) - if !ok { - bw = bufio.NewWriter(w) - ww = bw - } - aw := &textWriter{ - w: ww, - complete: true, - compact: compact, - } - - if tm, ok := pb.(encoding.TextMarshaler); ok { - text, err := tm.MarshalText() - if err != nil { - return err - } - if _, err = aw.Write(text); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil - } - // Dereference the received pointer so we don't have outer < and >. - v := reflect.Indirect(val) - if err := writeStruct(aw, v); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil -} - -// MarshalText writes a given protocol buffer in text format. -// The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { - return marshalText(w, pb, false) -} - -// MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, false) - return buf.String() -} - -// CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) } - -// CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { - var buf bytes.Buffer - marshalText(&buf, pb, true) - return buf.String() -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go deleted file mode 100644 index d1caeff5d9e04323d108f5b990f94326842e4bd0..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/golang/protobuf/proto/text_parser.go +++ /dev/null @@ -1,757 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for parsing the Text protocol buffer format. -// TODO: message sets. - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "unicode/utf8" -) - -type ParseError struct { - Message string - Line int // 1-based line number - Offset int // 0-based byte offset from start of input -} - -func (p *ParseError) Error() string { - if p.Line == 1 { - // show offset only for first line - return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) - } - return fmt.Sprintf("line %d: %v", p.Line, p.Message) -} - -type token struct { - value string - err *ParseError - line int // line number - offset int // byte number from start of input, not start of line - unquoted string // the unquoted version of value, if it was a quoted string -} - -func (t *token) String() string { - if t.err == nil { - return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) - } - return fmt.Sprintf("parse error: %v", t.err) -} - -type textParser struct { - s string // remaining input - done bool // whether the parsing is finished (success or error) - backed bool // whether back() was called - offset, line int - cur token -} - -func newTextParser(s string) *textParser { - p := new(textParser) - p.s = s - p.line = 1 - p.cur.line = 1 - return p -} - -func (p *textParser) errorf(format string, a ...interface{}) *ParseError { - pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} - p.cur.err = pe - p.done = true - return pe -} - -// Numbers and identifiers are matched by [-+._A-Za-z0-9] -func isIdentOrNumberChar(c byte) bool { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': - return true - case '0' <= c && c <= '9': - return true - } - switch c { - case '-', '+', '.', '_': - return true - } - return false -} - -func isWhitespace(c byte) bool { - switch c { - case ' ', '\t', '\n', '\r': - return true - } - return false -} - -func (p *textParser) skipWhitespace() { - i := 0 - for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { - if p.s[i] == '#' { - // comment; skip to end of line or input - for i < len(p.s) && p.s[i] != '\n' { - i++ - } - if i == len(p.s) { - break - } - } - if p.s[i] == '\n' { - p.line++ - } - i++ - } - p.offset += i - p.s = p.s[i:len(p.s)] - if len(p.s) == 0 { - p.done = true - } -} - -func (p *textParser) advance() { - // Skip whitespace - p.skipWhitespace() - if p.done { - return - } - - // Start of non-whitespace - p.cur.err = nil - p.cur.offset, p.cur.line = p.offset, p.line - p.cur.unquoted = "" - switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',': - // Single symbol - p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] - case '"', '\'': - // Quoted string - i := 1 - for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { - if p.s[i] == '\\' && i+1 < len(p.s) { - // skip escaped char - i++ - } - i++ - } - if i >= len(p.s) || p.s[i] != p.s[0] { - p.errorf("unmatched quote") - return - } - unq, err := unquoteC(p.s[1:i], rune(p.s[0])) - if err != nil { - p.errorf("invalid quoted string %v", p.s[0:i+1]) - return - } - p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] - p.cur.unquoted = unq - default: - i := 0 - for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { - i++ - } - if i == 0 { - p.errorf("unexpected byte %#x", p.s[0]) - return - } - p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] - } - p.offset += len(p.cur.value) -} - -var ( - errBadUTF8 = errors.New("proto: bad UTF-8") - errBadHex = errors.New("proto: bad hexadecimal") -) - -func unquoteC(s string, quote rune) (string, error) { - // This is based on C++'s tokenizer.cc. - // Despite its name, this is *not* parsing C syntax. - // For instance, "\0" is an invalid quoted string. - - // Avoid allocation in trivial cases. - simple := true - for _, r := range s { - if r == '\\' || r == quote { - simple = false - break - } - } - if simple { - return s, nil - } - - buf := make([]byte, 0, 3*len(s)/2) - for len(s) > 0 { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", errBadUTF8 - } - s = s[n:] - if r != '\\' { - if r < utf8.RuneSelf { - buf = append(buf, byte(r)) - } else { - buf = append(buf, string(r)...) - } - continue - } - - ch, tail, err := unescape(s) - if err != nil { - return "", err - } - buf = append(buf, ch...) - s = tail - } - return string(buf), nil -} - -func unescape(s string) (ch string, tail string, err error) { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", "", errBadUTF8 - } - s = s[n:] - switch r { - case 'a': - return "\a", s, nil - case 'b': - return "\b", s, nil - case 'f': - return "\f", s, nil - case 'n': - return "\n", s, nil - case 'r': - return "\r", s, nil - case 't': - return "\t", s, nil - case 'v': - return "\v", s, nil - case '?': - return "?", s, nil // trigraph workaround - case '\'', '"', '\\': - return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': - if len(s) < 2 { - return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) - } - base := 8 - ss := s[:2] - s = s[2:] - if r == 'x' || r == 'X' { - base = 16 - } else { - ss = string(r) + ss - } - i, err := strconv.ParseUint(ss, base, 8) - if err != nil { - return "", "", err - } - return string([]byte{byte(i)}), s, nil - case 'u', 'U': - n := 4 - if r == 'U' { - n = 8 - } - if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) - } - - bs := make([]byte, n/2) - for i := 0; i < n; i += 2 { - a, ok1 := unhex(s[i]) - b, ok2 := unhex(s[i+1]) - if !ok1 || !ok2 { - return "", "", errBadHex - } - bs[i/2] = a<<4 | b - } - s = s[n:] - return string(bs), s, nil - } - return "", "", fmt.Errorf(`unknown escape \%c`, r) -} - -// Adapted from src/pkg/strconv/quote.go. -func unhex(b byte) (v byte, ok bool) { - switch { - case '0' <= b && b <= '9': - return b - '0', true - case 'a' <= b && b <= 'f': - return b - 'a' + 10, true - case 'A' <= b && b <= 'F': - return b - 'A' + 10, true - } - return 0, false -} - -// Back off the parser by one token. Can only be done between calls to next(). -// It makes the next advance() a no-op. -func (p *textParser) back() { p.backed = true } - -// Advances the parser and returns the new current token. -func (p *textParser) next() *token { - if p.backed || p.done { - p.backed = false - return &p.cur - } - p.advance() - if p.done { - p.cur.value = "" - } else if len(p.cur.value) > 0 && p.cur.value[0] == '"' { - // Look for multiple quoted strings separated by whitespace, - // and concatenate them. - cat := p.cur - for { - p.skipWhitespace() - if p.done || p.s[0] != '"' { - break - } - p.advance() - if p.cur.err != nil { - return &p.cur - } - cat.value += " " + p.cur.value - cat.unquoted += p.cur.unquoted - } - p.done = false // parser may have seen EOF, but we want to return cat - p.cur = cat - } - return &p.cur -} - -func (p *textParser) consumeToken(s string) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != s { - p.back() - return p.errorf("expected %q, found %q", s, tok.value) - } - return nil -} - -// Return a RequiredNotSetError indicating which required field was not set. -func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < st.NumField(); i++ { - if !isNil(sv.Field(i)) { - continue - } - - props := sprops.Prop[i] - if props.Required { - return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} - } - } - return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen -} - -// Returns the index in the struct for the named field, as well as the parsed tag properties. -func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) { - sprops := GetProperties(st) - i, ok := sprops.decoderOrigNames[name] - if ok { - return i, sprops.Prop[i], true - } - return -1, nil, false -} - -// Consume a ':' from the input stream (if the next token is a colon), -// returning an error if a colon is needed but not present. -func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ":" { - // Colon is optional when the field is a group or message. - needColon := true - switch props.Wire { - case "group": - needColon = false - case "bytes": - // A "bytes" field is either a message, a string, or a repeated field; - // those three become *T, *string and []T respectively, so we can check for - // this field being a pointer to a non-string. - if typ.Kind() == reflect.Ptr { - // *T or *string - if typ.Elem().Kind() == reflect.String { - break - } - } else if typ.Kind() == reflect.Slice { - // []T or []*T - if typ.Elem().Kind() != reflect.Ptr { - break - } - } else if typ.Kind() == reflect.String { - // The proto3 exception is for a string field, - // which requires a colon. - break - } - needColon = false - } - if needColon { - return p.errorf("expected ':', found %q", tok.value) - } - p.back() - } - return nil -} - -func (p *textParser) readStruct(sv reflect.Value, terminator string) error { - st := sv.Type() - reqCount := GetProperties(st).reqCount - var reqFieldErr error - fieldSet := make(map[string]bool) - // A struct is a sequence of "name: value", terminated by one of - // '>' or '}', or the end of the input. A name may also be - // "[extension]". - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - if tok.value == "[" { - // Looks like an extension. - // - // TODO: Check whether we need to handle - // namespace rooted names (e.g. ".something.Foo"). - tok = p.next() - if tok.err != nil { - return tok.err - } - var desc *ExtensionDesc - // This could be faster, but it's functional. - // TODO: Do something smarter than a linear scan. - for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { - if d.Name == tok.value { - desc = d - break - } - } - if desc == nil { - return p.errorf("unrecognized extension %q", tok.value) - } - // Check the extension terminator. - tok = p.next() - if tok.err != nil { - return tok.err - } - if tok.value != "]" { - return p.errorf("unrecognized extension terminator %q", tok.value) - } - - props := &Properties{} - props.Parse(desc.Tag) - - typ := reflect.TypeOf(desc.ExtensionType) - if err := p.checkForColon(props, typ); err != nil { - return err - } - - rep := desc.repeated() - - // Read the extension structure, and set it in - // the value we're constructing. - var ext reflect.Value - if !rep { - ext = reflect.New(typ).Elem() - } else { - ext = reflect.New(typ.Elem()).Elem() - } - if err := p.readAny(ext, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - ep := sv.Addr().Interface().(extendableProto) - if !rep { - SetExtension(ep, desc, ext.Interface()) - } else { - old, err := GetExtension(ep, desc) - var sl reflect.Value - if err == nil { - sl = reflect.ValueOf(old) // existing slice - } else { - sl = reflect.MakeSlice(typ, 0, 1) - } - sl = reflect.Append(sl, ext) - SetExtension(ep, desc, sl.Interface()) - } - } else { - // This is a normal, non-extension field. - name := tok.value - fi, props, ok := structFieldByName(st, name) - if !ok { - return p.errorf("unknown field name %q in %v", name, st) - } - - dst := sv.Field(fi) - - if dst.Kind() == reflect.Map { - // Consume any colon. - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Construct the map if it doesn't already exist. - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - key := reflect.New(dst.Type().Key()).Elem() - val := reflect.New(dst.Type().Elem()).Elem() - - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // Technically the "key" and "value" could come in any order, - // but in practice they won't. - - tok := p.next() - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - if err := p.consumeToken("key"); err != nil { - return err - } - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.mkeyprop); err != nil { - return err - } - if err := p.consumeToken("value"); err != nil { - return err - } - if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.mvalprop); err != nil { - return err - } - if err := p.consumeToken(terminator); err != nil { - return err - } - - dst.SetMapIndex(key, val) - continue - } - - // Check that it's not already set if it's not a repeated field. - if !props.Repeated && fieldSet[name] { - return p.errorf("non-repeated field %q was repeated", name) - } - - if err := p.checkForColon(props, st.Field(fi).Type); err != nil { - return err - } - - // Parse into the field. - fieldSet[name] = true - if err := p.readAny(dst, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } else if props.Required { - reqCount-- - } - } - - // For backward compatibility, permit a semicolon or comma after a field. - tok = p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ";" && tok.value != "," { - p.back() - } - } - - if reqCount > 0 { - return p.missingRequiredFieldError(sv) - } - return reqFieldErr -} - -func (p *textParser) readAny(v reflect.Value, props *Properties) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "" { - return p.errorf("unexpected EOF") - } - - switch fv := v; fv.Kind() { - case reflect.Slice: - at := v.Type() - if at.Elem().Kind() == reflect.Uint8 { - // Special case for []byte - if tok.value[0] != '"' && tok.value[0] != '\'' { - // Deliberately written out here, as the error after - // this switch statement would write "invalid []byte: ...", - // which is not as user-friendly. - return p.errorf("invalid string: %v", tok.value) - } - bytes := []byte(tok.unquoted) - fv.Set(reflect.ValueOf(bytes)) - return nil - } - // Repeated field. May already exist. - flen := fv.Len() - if flen == fv.Cap() { - nav := reflect.MakeSlice(at, flen, 2*flen+1) - reflect.Copy(nav, fv) - fv.Set(nav) - } - fv.SetLen(flen + 1) - - // Read one. - p.back() - return p.readAny(fv.Index(flen), props) - case reflect.Bool: - // Either "true", "false", 1 or 0. - switch tok.value { - case "true", "1": - fv.SetBool(true) - return nil - case "false", "0": - fv.SetBool(false) - return nil - } - case reflect.Float32, reflect.Float64: - v := tok.value - // Ignore 'f' for compatibility with output generated by C++, but don't - // remove 'f' when the value is "-inf" or "inf". - if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { - v = v[:len(v)-1] - } - if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { - fv.SetFloat(f) - return nil - } - case reflect.Int32: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - fv.SetInt(x) - return nil - } - - if len(props.Enum) == 0 { - break - } - m, ok := enumValueMaps[props.Enum] - if !ok { - break - } - x, ok := m[tok.value] - if !ok { - break - } - fv.SetInt(int64(x)) - return nil - case reflect.Int64: - if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { - fv.SetInt(x) - return nil - } - - case reflect.Ptr: - // A basic field (indirected through pointer), or a repeated message/group - p.back() - fv.Set(reflect.New(fv.Type().Elem())) - return p.readAny(fv.Elem(), props) - case reflect.String: - if tok.value[0] == '"' || tok.value[0] == '\'' { - fv.SetString(tok.unquoted) - return nil - } - case reflect.Struct: - var terminator string - switch tok.value { - case "{": - terminator = "}" - case "<": - terminator = ">" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - // TODO: Handle nested messages which implement encoding.TextUnmarshaler. - return p.readStruct(fv, terminator) - case reflect.Uint32: - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(uint64(x)) - return nil - } - case reflect.Uint64: - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - fv.SetUint(x) - return nil - } - } - return p.errorf("invalid %v: %v", v.Type(), tok.value) -} - -// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb -// before starting to unmarshal, so any existing data in pb is always removed. -// If a required field is not set and no other error occurs, -// UnmarshalText returns *RequiredNotSetError. -func UnmarshalText(s string, pb Message) error { - if um, ok := pb.(encoding.TextUnmarshaler); ok { - err := um.UnmarshalText([]byte(s)) - return err - } - pb.Reset() - v := reflect.ValueOf(pb) - if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { - return pe - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/LICENSE deleted file mode 100644 index bdc403653e0a053959f28d1d83f72aab72ff20ac..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2015 The Linux Foundation. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/config.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/config.go deleted file mode 100644 index ba66ff1c63f9ddf3f53e567b9c19c8d36631ab4e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/config.go +++ /dev/null @@ -1,412 +0,0 @@ -package specs - -import "os" - -// Spec is the base configuration for the container. It specifies platform -// independent configuration. This information must be included when the -// bundle is packaged for distribution. -type Spec struct { - // Version is the version of the specification that is supported. - Version string `json:"ociVersion"` - // Platform is the host information for OS and Arch. - Platform Platform `json:"platform"` - // Process is the container's main process. - Process Process `json:"process"` - // Root is the root information for the container's filesystem. - Root Root `json:"root"` - // Hostname is the container's host name. - Hostname string `json:"hostname,omitempty"` - // Mounts profile configuration for adding mounts to the container's filesystem. - Mounts []Mount `json:"mounts"` - // Hooks are the commands run at various lifecycle events of the container. - Hooks Hooks `json:"hooks"` - // Annotations is an unstructured key value map that may be set by external tools to store and retrieve arbitrary metadata. - Annotations map[string]string `json:"annotations,omitempty"` - - // Linux is platform specific configuration for Linux based containers. - Linux Linux `json:"linux" platform:"linux"` -} - -// Process contains information to start a specific application inside the container. -type Process struct { - // Terminal creates an interactive terminal for the container. - Terminal bool `json:"terminal"` - // User specifies user information for the process. - User User `json:"user"` - // Args specifies the binary and arguments for the application to execute. - Args []string `json:"args"` - // Env populates the process environment for the process. - Env []string `json:"env,omitempty"` - // Cwd is the current working directory for the process and must be - // relative to the container's root. - Cwd string `json:"cwd"` - // Capabilities are Linux capabilities that are kept for the container. - Capabilities []string `json:"capabilities,omitempty" platform:"linux"` - // Rlimits specifies rlimit options to apply to the process. - Rlimits []Rlimit `json:"rlimits,omitempty"` - // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. - NoNewPrivileges bool `json:"noNewPrivileges,omitempty"` - - // ApparmorProfile specified the apparmor profile for the container. (this field is platform dependent) - ApparmorProfile string `json:"apparmorProfile,omitempty" platform:"linux"` - // SelinuxProcessLabel specifies the selinux context that the container process is run as. (this field is platform dependent) - SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"` -} - -// User specifies Linux specific user and group information for the container's -// main process. -type User struct { - // UID is the user id. (this field is platform dependent) - UID uint32 `json:"uid,omitempty" platform:"linux"` - // GID is the group id. (this field is platform dependent) - GID uint32 `json:"gid,omitempty" platform:"linux"` - // AdditionalGids are additional group ids set for the container's process. (this field is platform dependent) - AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux"` -} - -// Root contains information about the container's root filesystem on the host. -type Root struct { - // Path is the absolute path to the container's root filesystem. - Path string `json:"path"` - // Readonly makes the root filesystem for the container readonly before the process is executed. - Readonly bool `json:"readonly"` -} - -// Platform specifies OS and arch information for the host system that the container -// is created for. -type Platform struct { - // OS is the operating system. - OS string `json:"os"` - // Arch is the architecture - Arch string `json:"arch"` -} - -// Mount specifies a mount for a container. -type Mount struct { - // Destination is the path where the mount will be placed relative to the container's root. The path and child directories MUST exist, a runtime MUST NOT create directories automatically to a mount point. - Destination string `json:"destination"` - // Type specifies the mount kind. - Type string `json:"type"` - // Source specifies the source path of the mount. In the case of bind mounts on - // Linux based systems this would be the file on the host. - Source string `json:"source"` - // Options are fstab style mount options. - Options []string `json:"options,omitempty"` -} - -// Hook specifies a command that is run at a particular event in the lifecycle of a container -type Hook struct { - Path string `json:"path"` - Args []string `json:"args,omitempty"` - Env []string `json:"env,omitempty"` -} - -// Hooks for container setup and teardown -type Hooks struct { - // Prestart is a list of hooks to be run before the container process is executed. - // On Linux, they are run after the container namespaces are created. - Prestart []Hook `json:"prestart,omitempty"` - // Poststart is a list of hooks to be run after the container process is started. - Poststart []Hook `json:"poststart,omitempty"` - // Poststop is a list of hooks to be run after the container process exits. - Poststop []Hook `json:"poststop,omitempty"` -} - -// Linux contains platform specific configuration for Linux based containers. -type Linux struct { - // UIDMapping specifies user mappings for supporting user namespaces on Linux. - UIDMappings []IDMapping `json:"uidMappings,omitempty"` - // GIDMapping specifies group mappings for supporting user namespaces on Linux. - GIDMappings []IDMapping `json:"gidMappings,omitempty"` - // Sysctl are a set of key value pairs that are set for the container on start - Sysctl map[string]string `json:"sysctl,omitempty"` - // Resources contain cgroup information for handling resource constraints - // for the container - Resources *Resources `json:"resources,omitempty"` - // CgroupsPath specifies the path to cgroups that are created and/or joined by the container. - // The path is expected to be relative to the cgroups mountpoint. - // If resources are specified, the cgroups at CgroupsPath will be updated based on resources. - CgroupsPath *string `json:"cgroupsPath,omitempty"` - // Namespaces contains the namespaces that are created and/or joined by the container - Namespaces []Namespace `json:"namespaces"` - // Devices are a list of device nodes that are created for the container - Devices []Device `json:"devices"` - // Seccomp specifies the seccomp security settings for the container. - Seccomp *Seccomp `json:"seccomp,omitempty"` - // RootfsPropagation is the rootfs mount propagation mode for the container. - RootfsPropagation string `json:"rootfsPropagation,omitempty"` -} - -// Namespace is the configuration for a Linux namespace -type Namespace struct { - // Type is the type of Linux namespace - Type NamespaceType `json:"type"` - // Path is a path to an existing namespace persisted on disk that can be joined - // and is of the same type - Path string `json:"path,omitempty"` -} - -// NamespaceType is one of the Linux namespaces -type NamespaceType string - -const ( - // PIDNamespace for isolating process IDs - PIDNamespace NamespaceType = "pid" - // NetworkNamespace for isolating network devices, stacks, ports, etc - NetworkNamespace = "network" - // MountNamespace for isolating mount points - MountNamespace = "mount" - // IPCNamespace for isolating System V IPC, POSIX message queues - IPCNamespace = "ipc" - // UTSNamespace for isolating hostname and NIS domain name - UTSNamespace = "uts" - // UserNamespace for isolating user and group IDs - UserNamespace = "user" -) - -// IDMapping specifies UID/GID mappings -type IDMapping struct { - // HostID is the UID/GID of the host user or group - HostID uint32 `json:"hostID"` - // ContainerID is the UID/GID of the container's user or group - ContainerID uint32 `json:"containerID"` - // Size is the length of the range of IDs mapped between the two namespaces - Size uint32 `json:"size"` -} - -// Rlimit type and restrictions -type Rlimit struct { - // Type of the rlimit to set - Type string `json:"type"` - // Hard is the hard limit for the specified type - Hard uint64 `json:"hard"` - // Soft is the soft limit for the specified type - Soft uint64 `json:"soft"` -} - -// HugepageLimit structure corresponds to limiting kernel hugepages -type HugepageLimit struct { - // Pagesize is the hugepage size - Pagesize *string `json:"pageSize,omitempty"` - // Limit is the limit of "hugepagesize" hugetlb usage - Limit *uint64 `json:"limit,omitempty"` -} - -// InterfacePriority for network interfaces -type InterfacePriority struct { - // Name is the name of the network interface - Name string `json:"name"` - // Priority for the interface - Priority uint32 `json:"priority"` -} - -// blockIODevice holds major:minor format supported in blkio cgroup -type blockIODevice struct { - // Major is the device's major number. - Major int64 `json:"major"` - // Minor is the device's minor number. - Minor int64 `json:"minor"` -} - -// WeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice -type WeightDevice struct { - blockIODevice - // Weight is the bandwidth rate for the device, range is from 10 to 1000 - Weight *uint16 `json:"weight,omitempty"` - // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only - LeafWeight *uint16 `json:"leafWeight,omitempty"` -} - -// ThrottleDevice struct holds a `major:minor rate_per_second` pair -type ThrottleDevice struct { - blockIODevice - // Rate is the IO rate limit per cgroup per device - Rate *uint64 `json:"rate,omitempty"` -} - -// BlockIO for Linux cgroup 'blkio' resource management -type BlockIO struct { - // Specifies per cgroup weight, range is from 10 to 1000 - Weight *uint16 `json:"blkioWeight,omitempty"` - // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only - LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"` - // Weight per cgroup per device, can override BlkioWeight - WeightDevice []WeightDevice `json:"blkioWeightDevice,omitempty"` - // IO read rate limit per cgroup per device, bytes per second - ThrottleReadBpsDevice []ThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"` - // IO write rate limit per cgroup per device, bytes per second - ThrottleWriteBpsDevice []ThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"` - // IO read rate limit per cgroup per device, IO per second - ThrottleReadIOPSDevice []ThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"` - // IO write rate limit per cgroup per device, IO per second - ThrottleWriteIOPSDevice []ThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"` -} - -// Memory for Linux cgroup 'memory' resource management -type Memory struct { - // Memory limit (in bytes). - Limit *uint64 `json:"limit,omitempty"` - // Memory reservation or soft_limit (in bytes). - Reservation *uint64 `json:"reservation,omitempty"` - // Total memory limit (memory + swap). - Swap *uint64 `json:"swap,omitempty"` - // Kernel memory limit (in bytes). - Kernel *uint64 `json:"kernel,omitempty"` - // Kernel memory limit for tcp (in bytes) - KernelTCP *uint64 `json:"kernelTCP"` - // How aggressive the kernel will swap memory pages. Range from 0 to 100. - Swappiness *uint64 `json:"swappiness,omitempty"` -} - -// CPU for Linux cgroup 'cpu' resource management -type CPU struct { - // CPU shares (relative weight (ratio) vs. other cgroups with cpu shares). - Shares *uint64 `json:"shares,omitempty"` - // CPU hardcap limit (in usecs). Allowed cpu time in a given period. - Quota *uint64 `json:"quota,omitempty"` - // CPU period to be used for hardcapping (in usecs). - Period *uint64 `json:"period,omitempty"` - // How much time realtime scheduling may use (in usecs). - RealtimeRuntime *uint64 `json:"realtimeRuntime,omitempty"` - // CPU period to be used for realtime scheduling (in usecs). - RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"` - // CPUs to use within the cpuset. Default is to use any CPU available. - Cpus *string `json:"cpus,omitempty"` - // List of memory nodes in the cpuset. Default is to use any available memory node. - Mems *string `json:"mems,omitempty"` -} - -// Pids for Linux cgroup 'pids' resource management (Linux 4.3) -type Pids struct { - // Maximum number of PIDs. Default is "no limit". - Limit *int64 `json:"limit,omitempty"` -} - -// Network identification and priority configuration -type Network struct { - // Set class identifier for container's network packets - ClassID *uint32 `json:"classID"` - // Set priority of network traffic for container - Priorities []InterfacePriority `json:"priorities,omitempty"` -} - -// Resources has container runtime resource constraints -type Resources struct { - // Devices are a list of device rules for the whitelist controller - Devices []DeviceCgroup `json:"devices"` - // DisableOOMKiller disables the OOM killer for out of memory conditions - DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"` - // Specify an oom_score_adj for the container. - OOMScoreAdj *int `json:"oomScoreAdj,omitempty"` - // Memory restriction configuration - Memory *Memory `json:"memory,omitempty"` - // CPU resource restriction configuration - CPU *CPU `json:"cpu,omitempty"` - // Task resource restriction configuration. - Pids *Pids `json:"pids,omitempty"` - // BlockIO restriction configuration - BlockIO *BlockIO `json:"blockIO,omitempty"` - // Hugetlb limit (in bytes) - HugepageLimits []HugepageLimit `json:"hugepageLimits,omitempty"` - // Network restriction configuration - Network *Network `json:"network,omitempty"` -} - -// Device represents the mknod information for a Linux special device file -type Device struct { - // Path to the device. - Path string `json:"path"` - // Device type, block, char, etc. - Type string `json:"type"` - // Major is the device's major number. - Major int64 `json:"major"` - // Minor is the device's minor number. - Minor int64 `json:"minor"` - // FileMode permission bits for the device. - FileMode *os.FileMode `json:"fileMode,omitempty"` - // UID of the device. - UID *uint32 `json:"uid,omitempty"` - // Gid of the device. - GID *uint32 `json:"gid,omitempty"` -} - -// DeviceCgroup represents a device rule for the whitelist controller -type DeviceCgroup struct { - // Allow or deny - Allow bool `json:"allow"` - // Device type, block, char, etc. - Type *string `json:"type,omitempty"` - // Major is the device's major number. - Major *int64 `json:"major,omitempty"` - // Minor is the device's minor number. - Minor *int64 `json:"minor,omitempty"` - // Cgroup access permissions format, rwm. - Access *string `json:"access,omitempty"` -} - -// Seccomp represents syscall restrictions -type Seccomp struct { - DefaultAction Action `json:"defaultAction"` - Architectures []Arch `json:"architectures"` - Syscalls []Syscall `json:"syscalls,omitempty"` -} - -// Arch used for additional architectures -type Arch string - -// Additional architectures permitted to be used for system calls -// By default only the native architecture of the kernel is permitted -const ( - ArchX86 Arch = "SCMP_ARCH_X86" - ArchX86_64 Arch = "SCMP_ARCH_X86_64" - ArchX32 Arch = "SCMP_ARCH_X32" - ArchARM Arch = "SCMP_ARCH_ARM" - ArchAARCH64 Arch = "SCMP_ARCH_AARCH64" - ArchMIPS Arch = "SCMP_ARCH_MIPS" - ArchMIPS64 Arch = "SCMP_ARCH_MIPS64" - ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32" - ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL" - ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64" - ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32" -) - -// Action taken upon Seccomp rule match -type Action string - -// Define actions for Seccomp rules -const ( - ActKill Action = "SCMP_ACT_KILL" - ActTrap Action = "SCMP_ACT_TRAP" - ActErrno Action = "SCMP_ACT_ERRNO" - ActTrace Action = "SCMP_ACT_TRACE" - ActAllow Action = "SCMP_ACT_ALLOW" -) - -// Operator used to match syscall arguments in Seccomp -type Operator string - -// Define operators for syscall arguments in Seccomp -const ( - OpNotEqual Operator = "SCMP_CMP_NE" - OpLessThan Operator = "SCMP_CMP_LT" - OpLessEqual Operator = "SCMP_CMP_LE" - OpEqualTo Operator = "SCMP_CMP_EQ" - OpGreaterEqual Operator = "SCMP_CMP_GE" - OpGreaterThan Operator = "SCMP_CMP_GT" - OpMaskedEqual Operator = "SCMP_CMP_MASKED_EQ" -) - -// Arg used for matching specific syscall arguments in Seccomp -type Arg struct { - Index uint `json:"index"` - Value uint64 `json:"value"` - ValueTwo uint64 `json:"valueTwo"` - Op Operator `json:"op"` -} - -// Syscall is used to match a syscall in Seccomp -type Syscall struct { - Name string `json:"name"` - Action Action `json:"action"` - Args []Arg `json:"args,omitempty"` -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/state.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/state.go deleted file mode 100644 index d3ad79d9c23f640fd7a26c79497a18ff515ad7bd..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/state.go +++ /dev/null @@ -1,13 +0,0 @@ -package specs - -// State holds information about the runtime state of the container. -type State struct { - // Version is the version of the specification that is supported. - Version string `json:"version"` - // ID is the container ID - ID string `json:"id"` - // Pid is the process id for the container's main process. - Pid int `json:"pid"` - // BundlePath is the path to the container's bundle directory. - BundlePath string `json:"bundlePath"` -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/version.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/version.go deleted file mode 100644 index f11c8978960fada59cc8fd93f7315ab199b518f3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/specs/specs-go/version.go +++ /dev/null @@ -1,18 +0,0 @@ -package specs - -import "fmt" - -const ( - // VersionMajor is for an API incompatible changes - VersionMajor = 0 - // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 4 - // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 0 - - // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "" -) - -// Version is the specification version that the package types support. -var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/LICENSE deleted file mode 100644 index 81cf60de29ef6ded599bedc36ac4dcf2ef511375..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2015 Matthew Heon <mheon@redhat.com> -Copyright (c) 2015 Paul Moore <pmoore@redhat.com> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -- Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go deleted file mode 100644 index cebafdfae8414da20c284412d6fffe8f2963aa96..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go +++ /dev/null @@ -1,827 +0,0 @@ -// +build linux - -// Public API specification for libseccomp Go bindings -// Contains public API for the bindings - -// Package seccomp rovides bindings for libseccomp, a library wrapping the Linux -// seccomp syscall. Seccomp enables an application to restrict system call use -// for itself and its children. -package seccomp - -import ( - "fmt" - "os" - "runtime" - "strings" - "sync" - "syscall" - "unsafe" -) - -// C wrapping code - -// #cgo LDFLAGS: -lseccomp -// #include <stdlib.h> -// #include <seccomp.h> -import "C" - -// Exported types - -// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a -// per-architecture basis. -type ScmpArch uint - -// ScmpAction represents an action to be taken on a filter rule match in -// libseccomp -type ScmpAction uint - -// ScmpCompareOp represents a comparison operator which can be used in a filter -// rule -type ScmpCompareOp uint - -// ScmpCondition represents a rule in a libseccomp filter context -type ScmpCondition struct { - Argument uint `json:"argument,omitempty"` - Op ScmpCompareOp `json:"operator,omitempty"` - Operand1 uint64 `json:"operand_one,omitempty"` - Operand2 uint64 `json:"operand_two,omitempty"` -} - -// ScmpSyscall represents a Linux System Call -type ScmpSyscall int32 - -// Exported Constants - -const ( - // Valid architectures recognized by libseccomp - // ARM64 and all MIPS architectures are unsupported by versions of the - // library before v2.2 and will return errors if used - - // ArchInvalid is a placeholder to ensure uninitialized ScmpArch - // variables are invalid - ArchInvalid ScmpArch = iota - // ArchNative is the native architecture of the kernel - ArchNative ScmpArch = iota - // ArchX86 represents 32-bit x86 syscalls - ArchX86 ScmpArch = iota - // ArchAMD64 represents 64-bit x86-64 syscalls - ArchAMD64 ScmpArch = iota - // ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers) - ArchX32 ScmpArch = iota - // ArchARM represents 32-bit ARM syscalls - ArchARM ScmpArch = iota - // ArchARM64 represents 64-bit ARM syscalls - ArchARM64 ScmpArch = iota - // ArchMIPS represents 32-bit MIPS syscalls - ArchMIPS ScmpArch = iota - // ArchMIPS64 represents 64-bit MIPS syscalls - ArchMIPS64 ScmpArch = iota - // ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers) - ArchMIPS64N32 ScmpArch = iota - // ArchMIPSEL represents 32-bit MIPS syscalls (little endian) - ArchMIPSEL ScmpArch = iota - // ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian) - ArchMIPSEL64 ScmpArch = iota - // ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian, - // 32-bit pointers) - ArchMIPSEL64N32 ScmpArch = iota -) - -const ( - // Supported actions on filter match - - // ActInvalid is a placeholder to ensure uninitialized ScmpAction - // variables are invalid - ActInvalid ScmpAction = iota - // ActKill kills the process - ActKill ScmpAction = iota - // ActTrap throws SIGSYS - ActTrap ScmpAction = iota - // ActErrno causes the syscall to return a negative error code. This - // code can be set with the SetReturnCode method - ActErrno ScmpAction = iota - // ActTrace causes the syscall to notify tracing processes with the - // given error code. This code can be set with the SetReturnCode method - ActTrace ScmpAction = iota - // ActAllow permits the syscall to continue execution - ActAllow ScmpAction = iota -) - -const ( - // These are comparison operators used in conditional seccomp rules - // They are used to compare the value of a single argument of a syscall - // against a user-defined constant - - // CompareInvalid is a placeholder to ensure uninitialized ScmpCompareOp - // variables are invalid - CompareInvalid ScmpCompareOp = iota - // CompareNotEqual returns true if the argument is not equal to the - // given value - CompareNotEqual ScmpCompareOp = iota - // CompareLess returns true if the argument is less than the given value - CompareLess ScmpCompareOp = iota - // CompareLessOrEqual returns true if the argument is less than or equal - // to the given value - CompareLessOrEqual ScmpCompareOp = iota - // CompareEqual returns true if the argument is equal to the given value - CompareEqual ScmpCompareOp = iota - // CompareGreaterEqual returns true if the argument is greater than or - // equal to the given value - CompareGreaterEqual ScmpCompareOp = iota - // CompareGreater returns true if the argument is greater than the given - // value - CompareGreater ScmpCompareOp = iota - // CompareMaskedEqual returns true if the argument is equal to the given - // value, when masked (bitwise &) against the second given value - CompareMaskedEqual ScmpCompareOp = iota -) - -// Helpers for types - -// GetArchFromString returns an ScmpArch constant from a string representing an -// architecture -func GetArchFromString(arch string) (ScmpArch, error) { - switch strings.ToLower(arch) { - case "x86": - return ArchX86, nil - case "amd64", "x86-64", "x86_64", "x64": - return ArchAMD64, nil - case "x32": - return ArchX32, nil - case "arm": - return ArchARM, nil - case "arm64", "aarch64": - return ArchARM64, nil - case "mips": - return ArchMIPS, nil - case "mips64": - return ArchMIPS64, nil - case "mips64n32": - return ArchMIPS64N32, nil - case "mipsel": - return ArchMIPSEL, nil - case "mipsel64": - return ArchMIPSEL64, nil - case "mipsel64n32": - return ArchMIPSEL64N32, nil - default: - return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %s", arch) - } -} - -// String returns a string representation of an architecture constant -func (a ScmpArch) String() string { - switch a { - case ArchX86: - return "x86" - case ArchAMD64: - return "amd64" - case ArchX32: - return "x32" - case ArchARM: - return "arm" - case ArchARM64: - return "arm64" - case ArchMIPS: - return "mips" - case ArchMIPS64: - return "mips64" - case ArchMIPS64N32: - return "mips64n32" - case ArchMIPSEL: - return "mipsel" - case ArchMIPSEL64: - return "mipsel64" - case ArchMIPSEL64N32: - return "mipsel64n32" - case ArchNative: - return "native" - case ArchInvalid: - return "Invalid architecture" - default: - return "Unknown architecture" - } -} - -// String returns a string representation of a comparison operator constant -func (a ScmpCompareOp) String() string { - switch a { - case CompareNotEqual: - return "Not equal" - case CompareLess: - return "Less than" - case CompareLessOrEqual: - return "Less than or equal to" - case CompareEqual: - return "Equal" - case CompareGreaterEqual: - return "Greater than or equal to" - case CompareGreater: - return "Greater than" - case CompareMaskedEqual: - return "Masked equality" - case CompareInvalid: - return "Invalid comparison operator" - default: - return "Unrecognized comparison operator" - } -} - -// String returns a string representation of a seccomp match action -func (a ScmpAction) String() string { - switch a & 0xFFFF { - case ActKill: - return "Action: Kill Process" - case ActTrap: - return "Action: Send SIGSYS" - case ActErrno: - return fmt.Sprintf("Action: Return error code %d", (a >> 16)) - case ActTrace: - return fmt.Sprintf("Action: Notify tracing processes with code %d", - (a >> 16)) - case ActAllow: - return "Action: Allow system call" - default: - return "Unrecognized Action" - } -} - -// SetReturnCode adds a return code to a supporting ScmpAction, clearing any -// existing code Only valid on ActErrno and ActTrace. Takes no action otherwise. -// Accepts 16-bit return code as argument. -// Returns a valid ScmpAction of the original type with the new error code set. -func (a ScmpAction) SetReturnCode(code int16) ScmpAction { - aTmp := a & 0x0000FFFF - if aTmp == ActErrno || aTmp == ActTrace { - return (aTmp | (ScmpAction(code)&0xFFFF)<<16) - } - return a -} - -// GetReturnCode returns the return code of an ScmpAction -func (a ScmpAction) GetReturnCode() int16 { - return int16(a >> 16) -} - -// General utility functions - -// GetLibraryVersion returns the version of the library the bindings are built -// against. -// The version is formatted as follows: Major.Minor.Micro -func GetLibraryVersion() (major, minor, micro int) { - return verMajor, verMinor, verMicro -} - -// Syscall functions - -// GetName retrieves the name of a syscall from its number. -// Acts on any syscall number. -// Returns either a string containing the name of the syscall, or an error. -func (s ScmpSyscall) GetName() (string, error) { - return s.GetNameByArch(ArchNative) -} - -// GetNameByArch retrieves the name of a syscall from its number for a given -// architecture. -// Acts on any syscall number. -// Accepts a valid architecture constant. -// Returns either a string containing the name of the syscall, or an error. -// if the syscall is unrecognized or an issue occurred. -func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) { - if err := sanitizeArch(arch); err != nil { - return "", err - } - - cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s)) - if cString == nil { - return "", fmt.Errorf("could not resolve syscall name") - } - defer C.free(unsafe.Pointer(cString)) - - finalStr := C.GoString(cString) - return finalStr, nil -} - -// GetSyscallFromName returns the number of a syscall by name on the kernel's -// native architecture. -// Accepts a string containing the name of a syscall. -// Returns the number of the syscall, or an error if no syscall with that name -// was found. -func GetSyscallFromName(name string) (ScmpSyscall, error) { - cString := C.CString(name) - defer C.free(unsafe.Pointer(cString)) - - result := C.seccomp_syscall_resolve_name(cString) - if result == scmpError { - return 0, fmt.Errorf("could not resolve name to syscall") - } - - return ScmpSyscall(result), nil -} - -// GetSyscallFromNameByArch returns the number of a syscall by name for a given -// architecture's ABI. -// Accepts the name of a syscall and an architecture constant. -// Returns the number of the syscall, or an error if an invalid architecture is -// passed or a syscall with that name was not found. -func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) { - if err := sanitizeArch(arch); err != nil { - return 0, err - } - - cString := C.CString(name) - defer C.free(unsafe.Pointer(cString)) - - result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString) - if result == scmpError { - return 0, fmt.Errorf("could not resolve name to syscall") - } - - return ScmpSyscall(result), nil -} - -// MakeCondition creates and returns a new condition to attach to a filter rule. -// Associated rules will only match if this condition is true. -// Accepts the number the argument we are checking, and a comparison operator -// and value to compare to. -// The rule will match if argument $arg (zero-indexed) of the syscall is -// $COMPARE_OP the provided comparison value. -// Some comparison operators accept two values. Masked equals, for example, -// will mask $arg of the syscall with the second value provided (via bitwise -// AND) and then compare against the first value provided. -// For example, in the less than or equal case, if the syscall argument was -// 0 and the value provided was 1, the condition would match, as 0 is less -// than or equal to 1. -// Return either an error on bad argument or a valid ScmpCondition struct. -func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCondition, error) { - var condStruct ScmpCondition - - if comparison == CompareInvalid { - return condStruct, fmt.Errorf("invalid comparison operator") - } else if arg > 5 { - return condStruct, fmt.Errorf("syscalls only have up to 6 arguments") - } else if len(values) > 2 { - return condStruct, fmt.Errorf("conditions can have at most 2 arguments") - } else if len(values) == 0 { - return condStruct, fmt.Errorf("must provide at least one value to compare against") - } - - condStruct.Argument = arg - condStruct.Op = comparison - condStruct.Operand1 = values[0] - if len(values) == 2 { - condStruct.Operand2 = values[1] - } else { - condStruct.Operand2 = 0 // Unused - } - - return condStruct, nil -} - -// Utility Functions - -// GetNativeArch returns architecture token representing the native kernel -// architecture -func GetNativeArch() (ScmpArch, error) { - arch := C.seccomp_arch_native() - - return archFromNative(arch) -} - -// Public Filter API - -// ScmpFilter represents a filter context in libseccomp. -// A filter context is initially empty. Rules can be added to it, and it can -// then be loaded into the kernel. -type ScmpFilter struct { - filterCtx C.scmp_filter_ctx - valid bool - lock sync.Mutex -} - -// NewFilter creates and returns a new filter context. -// Accepts a default action to be taken for syscalls which match no rules in -// the filter. -// Returns a reference to a valid filter context, or nil and an error if the -// filter context could not be created or an invalid default action was given. -func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) { - if err := sanitizeAction(defaultAction); err != nil { - return nil, err - } - - fPtr := C.seccomp_init(defaultAction.toNative()) - if fPtr == nil { - return nil, fmt.Errorf("could not create filter") - } - - filter := new(ScmpFilter) - filter.filterCtx = fPtr - filter.valid = true - runtime.SetFinalizer(filter, filterFinalizer) - - return filter, nil -} - -// IsValid determines whether a filter context is valid to use. -// Some operations (Release and Merge) render filter contexts invalid and -// consequently prevent further use. -func (f *ScmpFilter) IsValid() bool { - f.lock.Lock() - defer f.lock.Unlock() - - return f.valid -} - -// Reset resets a filter context, removing all its existing state. -// Accepts a new default action to be taken for syscalls which do not match. -// Returns an error if the filter or action provided are invalid. -func (f *ScmpFilter) Reset(defaultAction ScmpAction) error { - f.lock.Lock() - defer f.lock.Unlock() - - if err := sanitizeAction(defaultAction); err != nil { - return err - } else if !f.valid { - return errBadFilter - } - - retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative()) - if retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// Release releases a filter context, freeing its memory. Should be called after -// loading into the kernel, when the filter is no longer needed. -// After calling this function, the given filter is no longer valid and cannot -// be used. -// Release() will be invoked automatically when a filter context is garbage -// collected, but can also be called manually to free memory. -func (f *ScmpFilter) Release() { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return - } - - f.valid = false - C.seccomp_release(f.filterCtx) -} - -// Merge merges two filter contexts. -// The source filter src will be released as part of the process, and will no -// longer be usable or valid after this call. -// To be merged, filters must NOT share any architectures, and all their -// attributes (Default Action, Bad Arch Action, No New Privs and TSync bools) -// must match. -// The filter src will be merged into the filter this is called on. -// The architectures of the src filter not present in the destination, and all -// associated rules, will be added to the destination. -// Returns an error if merging the filters failed. -func (f *ScmpFilter) Merge(src *ScmpFilter) error { - f.lock.Lock() - defer f.lock.Unlock() - - src.lock.Lock() - defer src.lock.Unlock() - - if !src.valid || !f.valid { - return fmt.Errorf("one or more of the filter contexts is invalid or uninitialized") - } - - // Merge the filters - retCode := C.seccomp_merge(f.filterCtx, src.filterCtx) - if syscall.Errno(-1*retCode) == syscall.EINVAL { - return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter") - } else if retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - src.valid = false - - return nil -} - -// IsArchPresent checks if an architecture is present in a filter. -// If a filter contains an architecture, it uses its default action for -// syscalls which do not match rules in it, and its rules can match syscalls -// for that ABI. -// If a filter does not contain an architecture, all syscalls made to that -// kernel ABI will fail with the filter's default Bad Architecture Action -// (by default, killing the process). -// Accepts an architecture constant. -// Returns true if the architecture is present in the filter, false otherwise, -// and an error on an invalid filter context, architecture constant, or an -// issue with the call to libseccomp. -func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) { - f.lock.Lock() - defer f.lock.Unlock() - - if err := sanitizeArch(arch); err != nil { - return false, err - } else if !f.valid { - return false, errBadFilter - } - - retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative()) - if syscall.Errno(-1*retCode) == syscall.EEXIST { - // -EEXIST is "arch not present" - return false, nil - } else if retCode != 0 { - return false, syscall.Errno(-1 * retCode) - } - - return true, nil -} - -// AddArch adds an architecture to the filter. -// Accepts an architecture constant. -// Returns an error on invalid filter context or architecture token, or an -// issue with the call to libseccomp. -func (f *ScmpFilter) AddArch(arch ScmpArch) error { - f.lock.Lock() - defer f.lock.Unlock() - - if err := sanitizeArch(arch); err != nil { - return err - } else if !f.valid { - return errBadFilter - } - - // Libseccomp returns -EEXIST if the specified architecture is already - // present. Succeed silently in this case, as it's not fatal, and the - // architecture is present already. - retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative()) - if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// RemoveArch removes an architecture from the filter. -// Accepts an architecture constant. -// Returns an error on invalid filter context or architecture token, or an -// issue with the call to libseccomp. -func (f *ScmpFilter) RemoveArch(arch ScmpArch) error { - f.lock.Lock() - defer f.lock.Unlock() - - if err := sanitizeArch(arch); err != nil { - return err - } else if !f.valid { - return errBadFilter - } - - // Similar to AddArch, -EEXIST is returned if the arch is not present - // Succeed silently in that case, this is not fatal and the architecture - // is not present in the filter after RemoveArch - retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative()) - if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// Load loads a filter context into the kernel. -// Returns an error if the filter context is invalid or the syscall failed. -func (f *ScmpFilter) Load() error { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return errBadFilter - } - - if retCode := C.seccomp_load(f.filterCtx); retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// GetDefaultAction returns the default action taken on a syscall which does not -// match a rule in the filter, or an error if an issue was encountered -// retrieving the value. -func (f *ScmpFilter) GetDefaultAction() (ScmpAction, error) { - action, err := f.getFilterAttr(filterAttrActDefault) - if err != nil { - return 0x0, err - } - - return actionFromNative(action) -} - -// GetBadArchAction returns the default action taken on a syscall for an -// architecture not in the filter, or an error if an issue was encountered -// retrieving the value. -func (f *ScmpFilter) GetBadArchAction() (ScmpAction, error) { - action, err := f.getFilterAttr(filterAttrActBadArch) - if err != nil { - return 0x0, err - } - - return actionFromNative(action) -} - -// GetNoNewPrivsBit returns the current state the No New Privileges bit will be set -// to on the filter being loaded, or an error if an issue was encountered -// retrieving the value. -// The No New Privileges bit tells the kernel that new processes run with exec() -// cannot gain more privileges than the process that ran exec(). -// For example, a process with No New Privileges set would be unable to exec -// setuid/setgid executables. -func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) { - noNewPrivs, err := f.getFilterAttr(filterAttrNNP) - if err != nil { - return false, err - } - - if noNewPrivs == 0 { - return false, nil - } - - return true, nil -} - -// GetTsyncBit returns whether Thread Synchronization will be enabled on the -// filter being loaded, or an error if an issue was encountered retrieving the -// value. -// Thread Sync ensures that all members of the thread group of the calling -// process will share the same Seccomp filter set. -// Tsync is a fairly recent addition to the Linux kernel and older kernels -// lack support. If the running kernel does not support Tsync and it is -// requested in a filter, Libseccomp will not enable TSync support and will -// proceed as normal. -// This function is unavailable before v2.2 of libseccomp and will return an -// error. -func (f *ScmpFilter) GetTsyncBit() (bool, error) { - tSync, err := f.getFilterAttr(filterAttrTsync) - if err != nil { - return false, err - } - - if tSync == 0 { - return false, nil - } - - return true, nil -} - -// SetBadArchAction sets the default action taken on a syscall for an -// architecture not in the filter, or an error if an issue was encountered -// setting the value. -func (f *ScmpFilter) SetBadArchAction(action ScmpAction) error { - if err := sanitizeAction(action); err != nil { - return err - } - - return f.setFilterAttr(filterAttrActBadArch, action.toNative()) -} - -// SetNoNewPrivsBit sets the state of the No New Privileges bit, which will be -// applied on filter load, or an error if an issue was encountered setting the -// value. -// Filters with No New Privileges set to 0 can only be loaded if the process -// has the CAP_SYS_ADMIN capability. -func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error { - var toSet C.uint32_t = 0x0 - - if state { - toSet = 0x1 - } - - return f.setFilterAttr(filterAttrNNP, toSet) -} - -// SetTsync sets whether Thread Synchronization will be enabled on the filter -// being loaded. Returns an error if setting Tsync failed, or the filter is -// invalid. -// Thread Sync ensures that all members of the thread group of the calling -// process will share the same Seccomp filter set. -// Tsync is a fairly recent addition to the Linux kernel and older kernels -// lack support. If the running kernel does not support Tsync and it is -// requested in a filter, Libseccomp will not enable TSync support and will -// proceed as normal. -// This function is unavailable before v2.2 of libseccomp and will return an -// error. -func (f *ScmpFilter) SetTsync(enable bool) error { - var toSet C.uint32_t = 0x0 - - if enable { - toSet = 0x1 - } - - return f.setFilterAttr(filterAttrTsync, toSet) -} - -// SetSyscallPriority sets a syscall's priority. -// This provides a hint to the filter generator in libseccomp about the -// importance of this syscall. High-priority syscalls are placed -// first in the filter code, and incur less overhead (at the expense of -// lower-priority syscalls). -func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return errBadFilter - } - - if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call), - C.uint8_t(priority)); retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// AddRule adds a single rule for an unconditional action on a syscall. -// Accepts the number of the syscall and the action to be taken on the call -// being made. -// Returns an error if an issue was encountered adding the rule. -func (f *ScmpFilter) AddRule(call ScmpSyscall, action ScmpAction) error { - return f.addRuleGeneric(call, action, false, nil) -} - -// AddRuleExact adds a single rule for an unconditional action on a syscall. -// Accepts the number of the syscall and the action to be taken on the call -// being made. -// No modifications will be made to the rule, and it will fail to add if it -// cannot be applied to the current architecture without modification. -// The rule will function exactly as described, but it may not function identically -// (or be able to be applied to) all architectures. -// Returns an error if an issue was encountered adding the rule. -func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error { - return f.addRuleGeneric(call, action, true, nil) -} - -// AddRuleConditional adds a single rule for a conditional action on a syscall. -// Returns an error if an issue was encountered adding the rule. -// All conditions must match for the rule to match. -// There is a bug in library versions below v2.2.1 which can, in some cases, -// cause conditions to be lost when more than one are used. Consequently, -// AddRuleConditional is disabled on library versions lower than v2.2.1 -func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error { - return f.addRuleGeneric(call, action, false, conds) -} - -// AddRuleConditionalExact adds a single rule for a conditional action on a -// syscall. -// No modifications will be made to the rule, and it will fail to add if it -// cannot be applied to the current architecture without modification. -// The rule will function exactly as described, but it may not function identically -// (or be able to be applied to) all architectures. -// Returns an error if an issue was encountered adding the rule. -// There is a bug in library versions below v2.2.1 which can, in some cases, -// cause conditions to be lost when more than one are used. Consequently, -// AddRuleConditionalExact is disabled on library versions lower than v2.2.1 -func (f *ScmpFilter) AddRuleConditionalExact(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error { - return f.addRuleGeneric(call, action, true, conds) -} - -// ExportPFC output PFC-formatted, human-readable dump of a filter context's -// rules to a file. -// Accepts file to write to (must be open for writing). -// Returns an error if writing to the file fails. -func (f *ScmpFilter) ExportPFC(file *os.File) error { - f.lock.Lock() - defer f.lock.Unlock() - - fd := file.Fd() - - if !f.valid { - return errBadFilter - } - - if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// ExportBPF outputs Berkeley Packet Filter-formatted, kernel-readable dump of a -// filter context's rules to a file. -// Accepts file to write to (must be open for writing). -// Returns an error if writing to the file fails. -func (f *ScmpFilter) ExportBPF(file *os.File) error { - f.lock.Lock() - defer f.lock.Unlock() - - fd := file.Fd() - - if !f.valid { - return errBadFilter - } - - if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go deleted file mode 100644 index 306ed17570bef9ab6d031ba319e5639a75979b79..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go +++ /dev/null @@ -1,461 +0,0 @@ -// +build linux - -// Internal functions for libseccomp Go bindings -// No exported functions - -package seccomp - -import ( - "fmt" - "os" - "syscall" -) - -// Unexported C wrapping code - provides the C-Golang interface -// Get the seccomp header in scope -// Need stdlib.h for free() on cstrings - -// #cgo LDFLAGS: -lseccomp -/* -#include <stdlib.h> -#include <seccomp.h> - -#if SCMP_VER_MAJOR < 2 -#error Minimum supported version of Libseccomp is v2.1.0 -#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 1 -#error Minimum supported version of Libseccomp is v2.1.0 -#endif - -#define ARCH_BAD ~0 - -const uint32_t C_ARCH_BAD = ARCH_BAD; - -#ifndef SCMP_ARCH_AARCH64 -#define SCMP_ARCH_AARCH64 ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPS -#define SCMP_ARCH_MIPS ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPS64 -#define SCMP_ARCH_MIPS64 ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPS64N32 -#define SCMP_ARCH_MIPS64N32 ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPSEL -#define SCMP_ARCH_MIPSEL ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPSEL64 -#define SCMP_ARCH_MIPSEL64 ARCH_BAD -#endif - -#ifndef SCMP_ARCH_MIPSEL64N32 -#define SCMP_ARCH_MIPSEL64N32 ARCH_BAD -#endif - -const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE; -const uint32_t C_ARCH_X86 = SCMP_ARCH_X86; -const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64; -const uint32_t C_ARCH_X32 = SCMP_ARCH_X32; -const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM; -const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64; -const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS; -const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64; -const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32; -const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL; -const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64; -const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32; - -const uint32_t C_ACT_KILL = SCMP_ACT_KILL; -const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP; -const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0); -const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0); -const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW; - -// If TSync is not supported, make sure it doesn't map to a supported filter attribute -// Don't worry about major version < 2, the minimum version checks should catch that case -#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2 -#define SCMP_FLTATR_CTL_TSYNC _SCMP_CMP_MIN -#endif - -const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT; -const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH; -const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP; -const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC; - -const int C_CMP_NE = (int)SCMP_CMP_NE; -const int C_CMP_LT = (int)SCMP_CMP_LT; -const int C_CMP_LE = (int)SCMP_CMP_LE; -const int C_CMP_EQ = (int)SCMP_CMP_EQ; -const int C_CMP_GE = (int)SCMP_CMP_GE; -const int C_CMP_GT = (int)SCMP_CMP_GT; -const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ; - -const int C_VERSION_MAJOR = SCMP_VER_MAJOR; -const int C_VERSION_MINOR = SCMP_VER_MINOR; -const int C_VERSION_MICRO = SCMP_VER_MICRO; - -typedef struct scmp_arg_cmp* scmp_cast_t; - -// Wrapper to create an scmp_arg_cmp struct -void* -make_struct_arg_cmp( - unsigned int arg, - int compare, - uint64_t a, - uint64_t b - ) -{ - struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp)); - - s->arg = arg; - s->op = compare; - s->datum_a = a; - s->datum_b = b; - - return s; -} -*/ -import "C" - -// Nonexported types -type scmpFilterAttr uint32 - -// Nonexported constants - -const ( - filterAttrActDefault scmpFilterAttr = iota - filterAttrActBadArch scmpFilterAttr = iota - filterAttrNNP scmpFilterAttr = iota - filterAttrTsync scmpFilterAttr = iota -) - -const ( - // An error return from certain libseccomp functions - scmpError C.int = -1 - // Comparison boundaries to check for architecture validity - archStart ScmpArch = ArchNative - archEnd ScmpArch = ArchMIPSEL64N32 - // Comparison boundaries to check for action validity - actionStart ScmpAction = ActKill - actionEnd ScmpAction = ActAllow - // Comparison boundaries to check for comparison operator validity - compareOpStart ScmpCompareOp = CompareNotEqual - compareOpEnd ScmpCompareOp = CompareMaskedEqual -) - -var ( - // Error thrown on bad filter context - errBadFilter = fmt.Errorf("filter is invalid or uninitialized") - // Constants representing library major, minor, and micro versions - verMajor = int(C.C_VERSION_MAJOR) - verMinor = int(C.C_VERSION_MINOR) - verMicro = int(C.C_VERSION_MICRO) -) - -// Nonexported functions - -// Check if library version is greater than or equal to the given one -func checkVersionAbove(major, minor, micro int) bool { - return (verMajor > major) || - (verMajor == major && verMinor > minor) || - (verMajor == major && verMinor == minor && verMicro >= micro) -} - -// Init function: Verify library version is appropriate -func init() { - if !checkVersionAbove(2, 1, 0) { - fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.1.0, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO) - os.Exit(-1) - } -} - -// Filter helpers - -// Filter finalizer - ensure that kernel context for filters is freed -func filterFinalizer(f *ScmpFilter) { - f.Release() -} - -// Get a raw filter attribute -func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return 0x0, errBadFilter - } - - if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync { - return 0x0, fmt.Errorf("the thread synchronization attribute is not supported in this version of the library") - } - - var attribute C.uint32_t - - retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute) - if retCode != 0 { - return 0x0, syscall.Errno(-1 * retCode) - } - - return attribute, nil -} - -// Set a raw filter attribute -func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return errBadFilter - } - - if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync { - return fmt.Errorf("the thread synchronization attribute is not supported in this version of the library") - } - - retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value) - if retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// DOES NOT LOCK OR CHECK VALIDITY -// Assumes caller has already done this -// Wrapper for seccomp_rule_add_... functions -func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, cond C.scmp_cast_t) error { - var length C.uint - if cond != nil { - length = 1 - } else { - length = 0 - } - - var retCode C.int - if exact { - retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond) - } else { - retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond) - } - - if syscall.Errno(-1*retCode) == syscall.EFAULT { - return fmt.Errorf("unrecognized syscall") - } else if syscall.Errno(-1*retCode) == syscall.EPERM { - return fmt.Errorf("requested action matches default action of filter") - } else if retCode != 0 { - return syscall.Errno(-1 * retCode) - } - - return nil -} - -// Generic add function for filter rules -func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error { - f.lock.Lock() - defer f.lock.Unlock() - - if !f.valid { - return errBadFilter - } - - if len(conds) == 0 { - if err := f.addRuleWrapper(call, action, exact, nil); err != nil { - return err - } - } else { - // We don't support conditional filtering in library version v2.1 - if !checkVersionAbove(2, 2, 1) { - return fmt.Errorf("conditional filtering requires libseccomp version >= 2.2.1") - } - - for _, cond := range conds { - cmpStruct := C.make_struct_arg_cmp(C.uint(cond.Argument), cond.Op.toNative(), C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2)) - defer C.free(cmpStruct) - - if err := f.addRuleWrapper(call, action, exact, C.scmp_cast_t(cmpStruct)); err != nil { - return err - } - } - } - - return nil -} - -// Generic Helpers - -// Helper - Sanitize Arch token input -func sanitizeArch(in ScmpArch) error { - if in < archStart || in > archEnd { - return fmt.Errorf("unrecognized architecture") - } - - if in.toNative() == C.C_ARCH_BAD { - return fmt.Errorf("architecture is not supported on this version of the library") - } - - return nil -} - -func sanitizeAction(in ScmpAction) error { - inTmp := in & 0x0000FFFF - if inTmp < actionStart || inTmp > actionEnd { - return fmt.Errorf("unrecognized action") - } - - if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 { - return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno") - } - - return nil -} - -func sanitizeCompareOp(in ScmpCompareOp) error { - if in < compareOpStart || in > compareOpEnd { - return fmt.Errorf("unrecognized comparison operator") - } - - return nil -} - -func archFromNative(a C.uint32_t) (ScmpArch, error) { - switch a { - case C.C_ARCH_X86: - return ArchX86, nil - case C.C_ARCH_X86_64: - return ArchAMD64, nil - case C.C_ARCH_X32: - return ArchX32, nil - case C.C_ARCH_ARM: - return ArchARM, nil - case C.C_ARCH_NATIVE: - return ArchNative, nil - case C.C_ARCH_AARCH64: - return ArchARM64, nil - case C.C_ARCH_MIPS: - return ArchMIPS, nil - case C.C_ARCH_MIPS64: - return ArchMIPS64, nil - case C.C_ARCH_MIPS64N32: - return ArchMIPS64N32, nil - case C.C_ARCH_MIPSEL: - return ArchMIPSEL, nil - case C.C_ARCH_MIPSEL64: - return ArchMIPSEL64, nil - case C.C_ARCH_MIPSEL64N32: - return ArchMIPSEL64N32, nil - default: - return 0x0, fmt.Errorf("unrecognized architecture") - } -} - -// Only use with sanitized arches, no error handling -func (a ScmpArch) toNative() C.uint32_t { - switch a { - case ArchX86: - return C.C_ARCH_X86 - case ArchAMD64: - return C.C_ARCH_X86_64 - case ArchX32: - return C.C_ARCH_X32 - case ArchARM: - return C.C_ARCH_ARM - case ArchARM64: - return C.C_ARCH_AARCH64 - case ArchMIPS: - return C.C_ARCH_MIPS - case ArchMIPS64: - return C.C_ARCH_MIPS64 - case ArchMIPS64N32: - return C.C_ARCH_MIPS64N32 - case ArchMIPSEL: - return C.C_ARCH_MIPSEL - case ArchMIPSEL64: - return C.C_ARCH_MIPSEL64 - case ArchMIPSEL64N32: - return C.C_ARCH_MIPSEL64N32 - case ArchNative: - return C.C_ARCH_NATIVE - default: - return 0x0 - } -} - -// Only use with sanitized ops, no error handling -func (a ScmpCompareOp) toNative() C.int { - switch a { - case CompareNotEqual: - return C.C_CMP_NE - case CompareLess: - return C.C_CMP_LT - case CompareLessOrEqual: - return C.C_CMP_LE - case CompareEqual: - return C.C_CMP_EQ - case CompareGreaterEqual: - return C.C_CMP_GE - case CompareGreater: - return C.C_CMP_GT - case CompareMaskedEqual: - return C.C_CMP_MASKED_EQ - default: - return 0x0 - } -} - -func actionFromNative(a C.uint32_t) (ScmpAction, error) { - aTmp := a & 0xFFFF - switch a & 0xFFFF0000 { - case C.C_ACT_KILL: - return ActKill, nil - case C.C_ACT_TRAP: - return ActTrap, nil - case C.C_ACT_ERRNO: - return ActErrno.SetReturnCode(int16(aTmp)), nil - case C.C_ACT_TRACE: - return ActTrace.SetReturnCode(int16(aTmp)), nil - case C.C_ACT_ALLOW: - return ActAllow, nil - default: - return 0x0, fmt.Errorf("unrecognized action") - } -} - -// Only use with sanitized actions, no error handling -func (a ScmpAction) toNative() C.uint32_t { - switch a & 0xFFFF { - case ActKill: - return C.C_ACT_KILL - case ActTrap: - return C.C_ACT_TRAP - case ActErrno: - return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16) - case ActTrace: - return C.C_ACT_TRACE | (C.uint32_t(a) >> 16) - case ActAllow: - return C.C_ACT_ALLOW - default: - return 0x0 - } -} - -// Internal only, assumes safe attribute -func (a scmpFilterAttr) toNative() uint32 { - switch a { - case filterAttrActDefault: - return uint32(C.C_ATTRIBUTE_DEFAULT) - case filterAttrActBadArch: - return uint32(C.C_ATTRIBUTE_BADARCH) - case filterAttrNNP: - return uint32(C.C_ATTRIBUTE_NNP) - case filterAttrTsync: - return uint32(C.C_ATTRIBUTE_TSYNC) - default: - return 0x0 - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/LICENSE deleted file mode 100644 index 80dd96de77fab9a0e619fbfb6f675921fa96c51e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright 2013 Suryandaru Triandana <syndtr@gmail.com> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability.go deleted file mode 100644 index c13f4e52a9cfece36ef625b2d8f19180403c0a2d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Package capability provides utilities for manipulating POSIX capabilities. -package capability - -type Capabilities interface { - // Get check whether a capability present in the given - // capabilities set. The 'which' value should be one of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - Get(which CapType, what Cap) bool - - // Empty check whether all capability bits of the given capabilities - // set are zero. The 'which' value should be one of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - Empty(which CapType) bool - - // Full check whether all capability bits of the given capabilities - // set are one. The 'which' value should be one of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - Full(which CapType) bool - - // Set sets capabilities of the given capabilities sets. The - // 'which' value should be one or combination (OR'ed) of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - Set(which CapType, caps ...Cap) - - // Unset unsets capabilities of the given capabilities sets. The - // 'which' value should be one or combination (OR'ed) of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - Unset(which CapType, caps ...Cap) - - // Fill sets all bits of the given capabilities kind to one. The - // 'kind' value should be one or combination (OR'ed) of CAPS or - // BOUNDS. - Fill(kind CapType) - - // Clear sets all bits of the given capabilities kind to zero. The - // 'kind' value should be one or combination (OR'ed) of CAPS or - // BOUNDS. - Clear(kind CapType) - - // String return current capabilities state of the given capabilities - // set as string. The 'which' value should be one of EFFECTIVE, - // PERMITTED, INHERITABLE or BOUNDING. - StringCap(which CapType) string - - // String return current capabilities state as string. - String() string - - // Load load actual capabilities value. This will overwrite all - // outstanding changes. - Load() error - - // Apply apply the capabilities settings, so all changes will take - // effect. - Apply(kind CapType) error -} - -// NewPid create new initialized Capabilities object for given pid when it -// is nonzero, or for the current pid if pid is 0 -func NewPid(pid int) (Capabilities, error) { - return newPid(pid) -} - -// NewFile create new initialized Capabilities object for given named file. -func NewFile(name string) (Capabilities, error) { - return newFile(name) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_linux.go deleted file mode 100644 index 3dfcd398dcd7441bcbe533f2981499e62367cb85..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_linux.go +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package capability - -import ( - "bufio" - "errors" - "fmt" - "io" - "os" - "strings" - "syscall" -) - -var errUnknownVers = errors.New("unknown capability version") - -const ( - linuxCapVer1 = 0x19980330 - linuxCapVer2 = 0x20071026 - linuxCapVer3 = 0x20080522 -) - -var ( - capVers uint32 - capLastCap Cap -) - -func init() { - var hdr capHeader - capget(&hdr, nil) - capVers = hdr.version - - if initLastCap() == nil { - CAP_LAST_CAP = capLastCap - if capLastCap > 31 { - capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1 - } else { - capUpperMask = 0 - } - } -} - -func initLastCap() error { - if capLastCap != 0 { - return nil - } - - f, err := os.Open("/proc/sys/kernel/cap_last_cap") - if err != nil { - return err - } - defer f.Close() - - var b []byte = make([]byte, 11) - _, err = f.Read(b) - if err != nil { - return err - } - - fmt.Sscanf(string(b), "%d", &capLastCap) - - return nil -} - -func mkStringCap(c Capabilities, which CapType) (ret string) { - for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ { - if !c.Get(which, i) { - continue - } - if first { - first = false - } else { - ret += ", " - } - ret += i.String() - } - return -} - -func mkString(c Capabilities, max CapType) (ret string) { - ret = "{" - for i := CapType(1); i <= max; i <<= 1 { - ret += " " + i.String() + "=\"" - if c.Empty(i) { - ret += "empty" - } else if c.Full(i) { - ret += "full" - } else { - ret += c.StringCap(i) - } - ret += "\"" - } - ret += " }" - return -} - -func newPid(pid int) (c Capabilities, err error) { - switch capVers { - case linuxCapVer1: - p := new(capsV1) - p.hdr.version = capVers - p.hdr.pid = pid - c = p - case linuxCapVer2, linuxCapVer3: - p := new(capsV3) - p.hdr.version = capVers - p.hdr.pid = pid - c = p - default: - err = errUnknownVers - return - } - err = c.Load() - if err != nil { - c = nil - } - return -} - -type capsV1 struct { - hdr capHeader - data capData -} - -func (c *capsV1) Get(which CapType, what Cap) bool { - if what > 32 { - return false - } - - switch which { - case EFFECTIVE: - return (1<<uint(what))&c.data.effective != 0 - case PERMITTED: - return (1<<uint(what))&c.data.permitted != 0 - case INHERITABLE: - return (1<<uint(what))&c.data.inheritable != 0 - } - - return false -} - -func (c *capsV1) getData(which CapType) (ret uint32) { - switch which { - case EFFECTIVE: - ret = c.data.effective - case PERMITTED: - ret = c.data.permitted - case INHERITABLE: - ret = c.data.inheritable - } - return -} - -func (c *capsV1) Empty(which CapType) bool { - return c.getData(which) == 0 -} - -func (c *capsV1) Full(which CapType) bool { - return (c.getData(which) & 0x7fffffff) == 0x7fffffff -} - -func (c *capsV1) Set(which CapType, caps ...Cap) { - for _, what := range caps { - if what > 32 { - continue - } - - if which&EFFECTIVE != 0 { - c.data.effective |= 1 << uint(what) - } - if which&PERMITTED != 0 { - c.data.permitted |= 1 << uint(what) - } - if which&INHERITABLE != 0 { - c.data.inheritable |= 1 << uint(what) - } - } -} - -func (c *capsV1) Unset(which CapType, caps ...Cap) { - for _, what := range caps { - if what > 32 { - continue - } - - if which&EFFECTIVE != 0 { - c.data.effective &= ^(1 << uint(what)) - } - if which&PERMITTED != 0 { - c.data.permitted &= ^(1 << uint(what)) - } - if which&INHERITABLE != 0 { - c.data.inheritable &= ^(1 << uint(what)) - } - } -} - -func (c *capsV1) Fill(kind CapType) { - if kind&CAPS == CAPS { - c.data.effective = 0x7fffffff - c.data.permitted = 0x7fffffff - c.data.inheritable = 0 - } -} - -func (c *capsV1) Clear(kind CapType) { - if kind&CAPS == CAPS { - c.data.effective = 0 - c.data.permitted = 0 - c.data.inheritable = 0 - } -} - -func (c *capsV1) StringCap(which CapType) (ret string) { - return mkStringCap(c, which) -} - -func (c *capsV1) String() (ret string) { - return mkString(c, BOUNDING) -} - -func (c *capsV1) Load() (err error) { - return capget(&c.hdr, &c.data) -} - -func (c *capsV1) Apply(kind CapType) error { - if kind&CAPS == CAPS { - return capset(&c.hdr, &c.data) - } - return nil -} - -type capsV3 struct { - hdr capHeader - data [2]capData - bounds [2]uint32 -} - -func (c *capsV3) Get(which CapType, what Cap) bool { - var i uint - if what > 31 { - i = uint(what) >> 5 - what %= 32 - } - - switch which { - case EFFECTIVE: - return (1<<uint(what))&c.data[i].effective != 0 - case PERMITTED: - return (1<<uint(what))&c.data[i].permitted != 0 - case INHERITABLE: - return (1<<uint(what))&c.data[i].inheritable != 0 - case BOUNDING: - return (1<<uint(what))&c.bounds[i] != 0 - } - - return false -} - -func (c *capsV3) getData(which CapType, dest []uint32) { - switch which { - case EFFECTIVE: - dest[0] = c.data[0].effective - dest[1] = c.data[1].effective - case PERMITTED: - dest[0] = c.data[0].permitted - dest[1] = c.data[1].permitted - case INHERITABLE: - dest[0] = c.data[0].inheritable - dest[1] = c.data[1].inheritable - case BOUNDING: - dest[0] = c.bounds[0] - dest[1] = c.bounds[1] - } -} - -func (c *capsV3) Empty(which CapType) bool { - var data [2]uint32 - c.getData(which, data[:]) - return data[0] == 0 && data[1] == 0 -} - -func (c *capsV3) Full(which CapType) bool { - var data [2]uint32 - c.getData(which, data[:]) - if (data[0] & 0xffffffff) != 0xffffffff { - return false - } - return (data[1] & capUpperMask) == capUpperMask -} - -func (c *capsV3) Set(which CapType, caps ...Cap) { - for _, what := range caps { - var i uint - if what > 31 { - i = uint(what) >> 5 - what %= 32 - } - - if which&EFFECTIVE != 0 { - c.data[i].effective |= 1 << uint(what) - } - if which&PERMITTED != 0 { - c.data[i].permitted |= 1 << uint(what) - } - if which&INHERITABLE != 0 { - c.data[i].inheritable |= 1 << uint(what) - } - if which&BOUNDING != 0 { - c.bounds[i] |= 1 << uint(what) - } - } -} - -func (c *capsV3) Unset(which CapType, caps ...Cap) { - for _, what := range caps { - var i uint - if what > 31 { - i = uint(what) >> 5 - what %= 32 - } - - if which&EFFECTIVE != 0 { - c.data[i].effective &= ^(1 << uint(what)) - } - if which&PERMITTED != 0 { - c.data[i].permitted &= ^(1 << uint(what)) - } - if which&INHERITABLE != 0 { - c.data[i].inheritable &= ^(1 << uint(what)) - } - if which&BOUNDING != 0 { - c.bounds[i] &= ^(1 << uint(what)) - } - } -} - -func (c *capsV3) Fill(kind CapType) { - if kind&CAPS == CAPS { - c.data[0].effective = 0xffffffff - c.data[0].permitted = 0xffffffff - c.data[0].inheritable = 0 - c.data[1].effective = 0xffffffff - c.data[1].permitted = 0xffffffff - c.data[1].inheritable = 0 - } - - if kind&BOUNDS == BOUNDS { - c.bounds[0] = 0xffffffff - c.bounds[1] = 0xffffffff - } -} - -func (c *capsV3) Clear(kind CapType) { - if kind&CAPS == CAPS { - c.data[0].effective = 0 - c.data[0].permitted = 0 - c.data[0].inheritable = 0 - c.data[1].effective = 0 - c.data[1].permitted = 0 - c.data[1].inheritable = 0 - } - - if kind&BOUNDS == BOUNDS { - c.bounds[0] = 0 - c.bounds[1] = 0 - } -} - -func (c *capsV3) StringCap(which CapType) (ret string) { - return mkStringCap(c, which) -} - -func (c *capsV3) String() (ret string) { - return mkString(c, BOUNDING) -} - -func (c *capsV3) Load() (err error) { - err = capget(&c.hdr, &c.data[0]) - if err != nil { - return - } - - var status_path string - - if c.hdr.pid == 0 { - status_path = fmt.Sprintf("/proc/self/status") - } else { - status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid) - } - - f, err := os.Open(status_path) - if err != nil { - return - } - b := bufio.NewReader(f) - for { - line, e := b.ReadString('\n') - if e != nil { - if e != io.EOF { - err = e - } - break - } - if strings.HasPrefix(line, "CapB") { - fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) - break - } - } - f.Close() - - return -} - -func (c *capsV3) Apply(kind CapType) (err error) { - if kind&BOUNDS == BOUNDS { - var data [2]capData - err = capget(&c.hdr, &data[0]) - if err != nil { - return - } - if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 { - for i := Cap(0); i <= CAP_LAST_CAP; i++ { - if c.Get(BOUNDING, i) { - continue - } - err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0) - if err != nil { - // Ignore EINVAL since the capability may not be supported in this system. - if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL { - err = nil - continue - } - return - } - } - } - } - - if kind&CAPS == CAPS { - return capset(&c.hdr, &c.data[0]) - } - - return -} - -func newFile(path string) (c Capabilities, err error) { - c = &capsFile{path: path} - err = c.Load() - if err != nil { - c = nil - } - return -} - -type capsFile struct { - path string - data vfscapData -} - -func (c *capsFile) Get(which CapType, what Cap) bool { - var i uint - if what > 31 { - if c.data.version == 1 { - return false - } - i = uint(what) >> 5 - what %= 32 - } - - switch which { - case EFFECTIVE: - return (1<<uint(what))&c.data.effective[i] != 0 - case PERMITTED: - return (1<<uint(what))&c.data.data[i].permitted != 0 - case INHERITABLE: - return (1<<uint(what))&c.data.data[i].inheritable != 0 - } - - return false -} - -func (c *capsFile) getData(which CapType, dest []uint32) { - switch which { - case EFFECTIVE: - dest[0] = c.data.effective[0] - dest[1] = c.data.effective[1] - case PERMITTED: - dest[0] = c.data.data[0].permitted - dest[1] = c.data.data[1].permitted - case INHERITABLE: - dest[0] = c.data.data[0].inheritable - dest[1] = c.data.data[1].inheritable - } -} - -func (c *capsFile) Empty(which CapType) bool { - var data [2]uint32 - c.getData(which, data[:]) - return data[0] == 0 && data[1] == 0 -} - -func (c *capsFile) Full(which CapType) bool { - var data [2]uint32 - c.getData(which, data[:]) - if c.data.version == 0 { - return (data[0] & 0x7fffffff) == 0x7fffffff - } - if (data[0] & 0xffffffff) != 0xffffffff { - return false - } - return (data[1] & capUpperMask) == capUpperMask -} - -func (c *capsFile) Set(which CapType, caps ...Cap) { - for _, what := range caps { - var i uint - if what > 31 { - if c.data.version == 1 { - continue - } - i = uint(what) >> 5 - what %= 32 - } - - if which&EFFECTIVE != 0 { - c.data.effective[i] |= 1 << uint(what) - } - if which&PERMITTED != 0 { - c.data.data[i].permitted |= 1 << uint(what) - } - if which&INHERITABLE != 0 { - c.data.data[i].inheritable |= 1 << uint(what) - } - } -} - -func (c *capsFile) Unset(which CapType, caps ...Cap) { - for _, what := range caps { - var i uint - if what > 31 { - if c.data.version == 1 { - continue - } - i = uint(what) >> 5 - what %= 32 - } - - if which&EFFECTIVE != 0 { - c.data.effective[i] &= ^(1 << uint(what)) - } - if which&PERMITTED != 0 { - c.data.data[i].permitted &= ^(1 << uint(what)) - } - if which&INHERITABLE != 0 { - c.data.data[i].inheritable &= ^(1 << uint(what)) - } - } -} - -func (c *capsFile) Fill(kind CapType) { - if kind&CAPS == CAPS { - c.data.effective[0] = 0xffffffff - c.data.data[0].permitted = 0xffffffff - c.data.data[0].inheritable = 0 - if c.data.version == 2 { - c.data.effective[1] = 0xffffffff - c.data.data[1].permitted = 0xffffffff - c.data.data[1].inheritable = 0 - } - } -} - -func (c *capsFile) Clear(kind CapType) { - if kind&CAPS == CAPS { - c.data.effective[0] = 0 - c.data.data[0].permitted = 0 - c.data.data[0].inheritable = 0 - if c.data.version == 2 { - c.data.effective[1] = 0 - c.data.data[1].permitted = 0 - c.data.data[1].inheritable = 0 - } - } -} - -func (c *capsFile) StringCap(which CapType) (ret string) { - return mkStringCap(c, which) -} - -func (c *capsFile) String() (ret string) { - return mkString(c, INHERITABLE) -} - -func (c *capsFile) Load() (err error) { - return getVfsCap(c.path, &c.data) -} - -func (c *capsFile) Apply(kind CapType) (err error) { - if kind&CAPS == CAPS { - return setVfsCap(c.path, &c.data) - } - return -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_noop.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_noop.go deleted file mode 100644 index 9bb3070c5ec5a468d94a5a44b1b146688c8c12ed..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_noop.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// +build !linux - -package capability - -import "errors" - -func newPid(pid int) (Capabilities, error) { - return nil, errors.New("not supported") -} - -func newFile(path string) (Capabilities, error) { - return nil, errors.New("not supported") -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum.go deleted file mode 100644 index fd0ce7fe8ee89cf8230f90534ee773042b80e037..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package capability - -type CapType uint - -func (c CapType) String() string { - switch c { - case EFFECTIVE: - return "effective" - case PERMITTED: - return "permitted" - case INHERITABLE: - return "inheritable" - case BOUNDING: - return "bounding" - case CAPS: - return "caps" - } - return "unknown" -} - -const ( - EFFECTIVE CapType = 1 << iota - PERMITTED - INHERITABLE - BOUNDING - - CAPS = EFFECTIVE | PERMITTED | INHERITABLE - BOUNDS = BOUNDING -) - -//go:generate go run enumgen/gen.go -type Cap int - -// POSIX-draft defined capabilities. -const ( - // In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this - // overrides the restriction of changing file ownership and group - // ownership. - CAP_CHOWN = Cap(0) - - // Override all DAC access, including ACL execute access if - // [_POSIX_ACL] is defined. Excluding DAC access covered by - // CAP_LINUX_IMMUTABLE. - CAP_DAC_OVERRIDE = Cap(1) - - // Overrides all DAC restrictions regarding read and search on files - // and directories, including ACL restrictions if [_POSIX_ACL] is - // defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. - CAP_DAC_READ_SEARCH = Cap(2) - - // Overrides all restrictions about allowed operations on files, where - // file owner ID must be equal to the user ID, except where CAP_FSETID - // is applicable. It doesn't override MAC and DAC restrictions. - CAP_FOWNER = Cap(3) - - // Overrides the following restrictions that the effective user ID - // shall match the file owner ID when setting the S_ISUID and S_ISGID - // bits on that file; that the effective group ID (or one of the - // supplementary group IDs) shall match the file owner ID when setting - // the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are - // cleared on successful return from chown(2) (not implemented). - CAP_FSETID = Cap(4) - - // Overrides the restriction that the real or effective user ID of a - // process sending a signal must match the real or effective user ID - // of the process receiving the signal. - CAP_KILL = Cap(5) - - // Allows setgid(2) manipulation - // Allows setgroups(2) - // Allows forged gids on socket credentials passing. - CAP_SETGID = Cap(6) - - // Allows set*uid(2) manipulation (including fsuid). - // Allows forged pids on socket credentials passing. - CAP_SETUID = Cap(7) - - // Linux-specific capabilities - - // Without VFS support for capabilities: - // Transfer any capability in your permitted set to any pid, - // remove any capability in your permitted set from any pid - // With VFS support for capabilities (neither of above, but) - // Add any capability from current's capability bounding set - // to the current process' inheritable set - // Allow taking bits out of capability bounding set - // Allow modification of the securebits for a process - CAP_SETPCAP = Cap(8) - - // Allow modification of S_IMMUTABLE and S_APPEND file attributes - CAP_LINUX_IMMUTABLE = Cap(9) - - // Allows binding to TCP/UDP sockets below 1024 - // Allows binding to ATM VCIs below 32 - CAP_NET_BIND_SERVICE = Cap(10) - - // Allow broadcasting, listen to multicast - CAP_NET_BROADCAST = Cap(11) - - // Allow interface configuration - // Allow administration of IP firewall, masquerading and accounting - // Allow setting debug option on sockets - // Allow modification of routing tables - // Allow setting arbitrary process / process group ownership on - // sockets - // Allow binding to any address for transparent proxying (also via NET_RAW) - // Allow setting TOS (type of service) - // Allow setting promiscuous mode - // Allow clearing driver statistics - // Allow multicasting - // Allow read/write of device-specific registers - // Allow activation of ATM control sockets - CAP_NET_ADMIN = Cap(12) - - // Allow use of RAW sockets - // Allow use of PACKET sockets - // Allow binding to any address for transparent proxying (also via NET_ADMIN) - CAP_NET_RAW = Cap(13) - - // Allow locking of shared memory segments - // Allow mlock and mlockall (which doesn't really have anything to do - // with IPC) - CAP_IPC_LOCK = Cap(14) - - // Override IPC ownership checks - CAP_IPC_OWNER = Cap(15) - - // Insert and remove kernel modules - modify kernel without limit - CAP_SYS_MODULE = Cap(16) - - // Allow ioperm/iopl access - // Allow sending USB messages to any device via /proc/bus/usb - CAP_SYS_RAWIO = Cap(17) - - // Allow use of chroot() - CAP_SYS_CHROOT = Cap(18) - - // Allow ptrace() of any process - CAP_SYS_PTRACE = Cap(19) - - // Allow configuration of process accounting - CAP_SYS_PACCT = Cap(20) - - // Allow configuration of the secure attention key - // Allow administration of the random device - // Allow examination and configuration of disk quotas - // Allow setting the domainname - // Allow setting the hostname - // Allow calling bdflush() - // Allow mount() and umount(), setting up new smb connection - // Allow some autofs root ioctls - // Allow nfsservctl - // Allow VM86_REQUEST_IRQ - // Allow to read/write pci config on alpha - // Allow irix_prctl on mips (setstacksize) - // Allow flushing all cache on m68k (sys_cacheflush) - // Allow removing semaphores - // Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores - // and shared memory - // Allow locking/unlocking of shared memory segment - // Allow turning swap on/off - // Allow forged pids on socket credentials passing - // Allow setting readahead and flushing buffers on block devices - // Allow setting geometry in floppy driver - // Allow turning DMA on/off in xd driver - // Allow administration of md devices (mostly the above, but some - // extra ioctls) - // Allow tuning the ide driver - // Allow access to the nvram device - // Allow administration of apm_bios, serial and bttv (TV) device - // Allow manufacturer commands in isdn CAPI support driver - // Allow reading non-standardized portions of pci configuration space - // Allow DDI debug ioctl on sbpcd driver - // Allow setting up serial ports - // Allow sending raw qic-117 commands - // Allow enabling/disabling tagged queuing on SCSI controllers and sending - // arbitrary SCSI commands - // Allow setting encryption key on loopback filesystem - // Allow setting zone reclaim policy - CAP_SYS_ADMIN = Cap(21) - - // Allow use of reboot() - CAP_SYS_BOOT = Cap(22) - - // Allow raising priority and setting priority on other (different - // UID) processes - // Allow use of FIFO and round-robin (realtime) scheduling on own - // processes and setting the scheduling algorithm used by another - // process. - // Allow setting cpu affinity on other processes - CAP_SYS_NICE = Cap(23) - - // Override resource limits. Set resource limits. - // Override quota limits. - // Override reserved space on ext2 filesystem - // Modify data journaling mode on ext3 filesystem (uses journaling - // resources) - // NOTE: ext2 honors fsuid when checking for resource overrides, so - // you can override using fsuid too - // Override size restrictions on IPC message queues - // Allow more than 64hz interrupts from the real-time clock - // Override max number of consoles on console allocation - // Override max number of keymaps - CAP_SYS_RESOURCE = Cap(24) - - // Allow manipulation of system clock - // Allow irix_stime on mips - // Allow setting the real-time clock - CAP_SYS_TIME = Cap(25) - - // Allow configuration of tty devices - // Allow vhangup() of tty - CAP_SYS_TTY_CONFIG = Cap(26) - - // Allow the privileged aspects of mknod() - CAP_MKNOD = Cap(27) - - // Allow taking of leases on files - CAP_LEASE = Cap(28) - - CAP_AUDIT_WRITE = Cap(29) - CAP_AUDIT_CONTROL = Cap(30) - CAP_SETFCAP = Cap(31) - - // Override MAC access. - // The base kernel enforces no MAC policy. - // An LSM may enforce a MAC policy, and if it does and it chooses - // to implement capability based overrides of that policy, this is - // the capability it should use to do so. - CAP_MAC_OVERRIDE = Cap(32) - - // Allow MAC configuration or state changes. - // The base kernel requires no MAC configuration. - // An LSM may enforce a MAC policy, and if it does and it chooses - // to implement capability based checks on modifications to that - // policy or the data required to maintain it, this is the - // capability it should use to do so. - CAP_MAC_ADMIN = Cap(33) - - // Allow configuring the kernel's syslog (printk behaviour) - CAP_SYSLOG = Cap(34) - - // Allow triggering something that will wake the system - CAP_WAKE_ALARM = Cap(35) - - // Allow preventing system suspends - CAP_BLOCK_SUSPEND = Cap(36) - - // Allow reading audit messages from the kernel - CAP_AUDIT_READ = Cap(37) -) - -var ( - // Highest valid capability of the running kernel. - CAP_LAST_CAP = Cap(63) - - capUpperMask = ^uint32(0) -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum_gen.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum_gen.go deleted file mode 100644 index b9e6d2d5e1ee5cf97cf5b51a543a11875749441d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum_gen.go +++ /dev/null @@ -1,129 +0,0 @@ -// generated file; DO NOT EDIT - use go generate in directory with source - -package capability - -func (c Cap) String() string { - switch c { - case CAP_CHOWN: - return "chown" - case CAP_DAC_OVERRIDE: - return "dac_override" - case CAP_DAC_READ_SEARCH: - return "dac_read_search" - case CAP_FOWNER: - return "fowner" - case CAP_FSETID: - return "fsetid" - case CAP_KILL: - return "kill" - case CAP_SETGID: - return "setgid" - case CAP_SETUID: - return "setuid" - case CAP_SETPCAP: - return "setpcap" - case CAP_LINUX_IMMUTABLE: - return "linux_immutable" - case CAP_NET_BIND_SERVICE: - return "net_bind_service" - case CAP_NET_BROADCAST: - return "net_broadcast" - case CAP_NET_ADMIN: - return "net_admin" - case CAP_NET_RAW: - return "net_raw" - case CAP_IPC_LOCK: - return "ipc_lock" - case CAP_IPC_OWNER: - return "ipc_owner" - case CAP_SYS_MODULE: - return "sys_module" - case CAP_SYS_RAWIO: - return "sys_rawio" - case CAP_SYS_CHROOT: - return "sys_chroot" - case CAP_SYS_PTRACE: - return "sys_ptrace" - case CAP_SYS_PACCT: - return "sys_pacct" - case CAP_SYS_ADMIN: - return "sys_admin" - case CAP_SYS_BOOT: - return "sys_boot" - case CAP_SYS_NICE: - return "sys_nice" - case CAP_SYS_RESOURCE: - return "sys_resource" - case CAP_SYS_TIME: - return "sys_time" - case CAP_SYS_TTY_CONFIG: - return "sys_tty_config" - case CAP_MKNOD: - return "mknod" - case CAP_LEASE: - return "lease" - case CAP_AUDIT_WRITE: - return "audit_write" - case CAP_AUDIT_CONTROL: - return "audit_control" - case CAP_SETFCAP: - return "setfcap" - case CAP_MAC_OVERRIDE: - return "mac_override" - case CAP_MAC_ADMIN: - return "mac_admin" - case CAP_SYSLOG: - return "syslog" - case CAP_WAKE_ALARM: - return "wake_alarm" - case CAP_BLOCK_SUSPEND: - return "block_suspend" - case CAP_AUDIT_READ: - return "audit_read" - } - return "unknown" -} - -// List returns list of all supported capabilities -func List() []Cap { - return []Cap{ - CAP_CHOWN, - CAP_DAC_OVERRIDE, - CAP_DAC_READ_SEARCH, - CAP_FOWNER, - CAP_FSETID, - CAP_KILL, - CAP_SETGID, - CAP_SETUID, - CAP_SETPCAP, - CAP_LINUX_IMMUTABLE, - CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST, - CAP_NET_ADMIN, - CAP_NET_RAW, - CAP_IPC_LOCK, - CAP_IPC_OWNER, - CAP_SYS_MODULE, - CAP_SYS_RAWIO, - CAP_SYS_CHROOT, - CAP_SYS_PTRACE, - CAP_SYS_PACCT, - CAP_SYS_ADMIN, - CAP_SYS_BOOT, - CAP_SYS_NICE, - CAP_SYS_RESOURCE, - CAP_SYS_TIME, - CAP_SYS_TTY_CONFIG, - CAP_MKNOD, - CAP_LEASE, - CAP_AUDIT_WRITE, - CAP_AUDIT_CONTROL, - CAP_SETFCAP, - CAP_MAC_OVERRIDE, - CAP_MAC_ADMIN, - CAP_SYSLOG, - CAP_WAKE_ALARM, - CAP_BLOCK_SUSPEND, - CAP_AUDIT_READ, - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enumgen/gen.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enumgen/gen.go deleted file mode 100644 index 4c733809b1b68896f7c3d9dec19cd5da141f66ee..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enumgen/gen.go +++ /dev/null @@ -1,92 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "go/ast" - "go/format" - "go/parser" - "go/token" - "io/ioutil" - "log" - "os" - "strings" -) - -const fileName = "enum.go" -const genName = "enum_gen.go" - -type generator struct { - buf bytes.Buffer - caps []string -} - -func (g *generator) writeHeader() { - g.buf.WriteString("// generated file; DO NOT EDIT - use go generate in directory with source\n") - g.buf.WriteString("\n") - g.buf.WriteString("package capability") -} - -func (g *generator) writeStringFunc() { - g.buf.WriteString("\n") - g.buf.WriteString("func (c Cap) String() string {\n") - g.buf.WriteString("switch c {\n") - for _, cap := range g.caps { - fmt.Fprintf(&g.buf, "case %s:\n", cap) - fmt.Fprintf(&g.buf, "return \"%s\"\n", strings.ToLower(cap[4:])) - } - g.buf.WriteString("}\n") - g.buf.WriteString("return \"unknown\"\n") - g.buf.WriteString("}\n") -} - -func (g *generator) writeListFunc() { - g.buf.WriteString("\n") - g.buf.WriteString("// List returns list of all supported capabilities\n") - g.buf.WriteString("func List() []Cap {\n") - g.buf.WriteString("return []Cap{\n") - for _, cap := range g.caps { - fmt.Fprintf(&g.buf, "%s,\n", cap) - } - g.buf.WriteString("}\n") - g.buf.WriteString("}\n") -} - -func main() { - fs := token.NewFileSet() - parsedFile, err := parser.ParseFile(fs, fileName, nil, 0) - if err != nil { - log.Fatal(err) - } - var caps []string - for _, decl := range parsedFile.Decls { - decl, ok := decl.(*ast.GenDecl) - if !ok || decl.Tok != token.CONST { - continue - } - for _, spec := range decl.Specs { - vspec := spec.(*ast.ValueSpec) - name := vspec.Names[0].Name - if strings.HasPrefix(name, "CAP_") { - caps = append(caps, name) - } - } - } - g := &generator{caps: caps} - g.writeHeader() - g.writeStringFunc() - g.writeListFunc() - src, err := format.Source(g.buf.Bytes()) - if err != nil { - fmt.Println("generated invalid Go code") - fmt.Println(g.buf.String()) - log.Fatal(err) - } - fi, err := os.Stat(fileName) - if err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(genName, src, fi.Mode().Perm()); err != nil { - log.Fatal(err) - } -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/syscall_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/syscall_linux.go deleted file mode 100644 index dd6f4540650b34352612f9dadd27f13b908499d9..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/syndtr/gocapability/capability/syscall_linux.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> -// All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package capability - -import ( - "syscall" - "unsafe" -) - -type capHeader struct { - version uint32 - pid int -} - -type capData struct { - effective uint32 - permitted uint32 - inheritable uint32 -} - -func capget(hdr *capHeader, data *capData) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) - if e1 != 0 { - err = e1 - } - return -} - -func capset(hdr *capHeader, data *capData) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) - if e1 != 0 { - err = e1 - } - return -} - -func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { - _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) - if e1 != 0 { - err = e1 - } - return -} - -const ( - vfsXattrName = "security.capability" - - vfsCapVerMask = 0xff000000 - vfsCapVer1 = 0x01000000 - vfsCapVer2 = 0x02000000 - - vfsCapFlagMask = ^vfsCapVerMask - vfsCapFlageffective = 0x000001 - - vfscapDataSizeV1 = 4 * (1 + 2*1) - vfscapDataSizeV2 = 4 * (1 + 2*2) -) - -type vfscapData struct { - magic uint32 - data [2]struct { - permitted uint32 - inheritable uint32 - } - effective [2]uint32 - version int8 -} - -var ( - _vfsXattrName *byte -) - -func init() { - _vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) -} - -func getVfsCap(path string, dest *vfscapData) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) - if e1 != 0 { - if e1 == syscall.ENODATA { - dest.version = 2 - return - } - err = e1 - } - switch dest.magic & vfsCapVerMask { - case vfsCapVer1: - dest.version = 1 - if r0 != vfscapDataSizeV1 { - return syscall.EINVAL - } - dest.data[1].permitted = 0 - dest.data[1].inheritable = 0 - case vfsCapVer2: - dest.version = 2 - if r0 != vfscapDataSizeV2 { - return syscall.EINVAL - } - default: - return syscall.EINVAL - } - if dest.magic&vfsCapFlageffective != 0 { - dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable - dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable - } else { - dest.effective[0] = 0 - dest.effective[1] = 0 - } - return -} - -func setVfsCap(path string, data *vfscapData) (err error) { - var _p0 *byte - _p0, err = syscall.BytePtrFromString(path) - if err != nil { - return - } - var size uintptr - if data.version == 1 { - data.magic = vfsCapVer1 - size = vfscapDataSizeV1 - } else if data.version == 2 { - data.magic = vfsCapVer2 - if data.effective[0] != 0 || data.effective[1] != 0 { - data.magic |= vfsCapFlageffective - } - size = vfscapDataSizeV2 - } else { - return syscall.EINVAL - } - _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) - if e1 != 0 { - err = e1 - } - return -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE deleted file mode 100644 index 9f64db8582cf97fa23685c44b5f8d8d9630da11b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE +++ /dev/null @@ -1,192 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2014 Vishvananda Ishaya. - Copyright 2014 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go deleted file mode 100644 index 9bbaf508e0c9cbcfa8d90bb75ce2a4475e5d12f6..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go +++ /dev/null @@ -1,43 +0,0 @@ -package netlink - -import ( - "fmt" - "net" - "strings" -) - -// Addr represents an IP address from netlink. Netlink ip addresses -// include a mask, so it stores the address as a net.IPNet. -type Addr struct { - *net.IPNet - Label string -} - -// String returns $ip/$netmask $label -func (a Addr) String() string { - return fmt.Sprintf("%s %s", a.IPNet, a.Label) -} - -// ParseAddr parses the string representation of an address in the -// form $ip/$netmask $label. The label portion is optional -func ParseAddr(s string) (*Addr, error) { - label := "" - parts := strings.Split(s, " ") - if len(parts) > 1 { - s = parts[0] - label = parts[1] - } - m, err := ParseIPNet(s) - if err != nil { - return nil, err - } - return &Addr{IPNet: m, Label: label}, nil -} - -// Equal returns true if both Addrs have the same net.IPNet value. -func (a Addr) Equal(x Addr) bool { - sizea, _ := a.Mask.Size() - sizeb, _ := x.Mask.Size() - // ignore label for comparison - return a.IP.Equal(x.IP) && sizea == sizeb -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go deleted file mode 100644 index 19aac0fb9799a749e8df60871f064f41ce3a1b73..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go +++ /dev/null @@ -1,128 +0,0 @@ -package netlink - -import ( - "fmt" - "net" - "strings" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -// AddrAdd will add an IP address to a link device. -// Equivalent to: `ip addr add $addr dev $link` -func AddrAdd(link Link, addr *Addr) error { - - req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - return addrHandle(link, addr, req) -} - -// AddrDel will delete an IP address from a link device. -// Equivalent to: `ip addr del $addr dev $link` -func AddrDel(link Link, addr *Addr) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK) - return addrHandle(link, addr, req) -} - -func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { - base := link.Attrs() - if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) { - return fmt.Errorf("label must begin with interface name") - } - ensureIndex(base) - - family := nl.GetIPFamily(addr.IP) - - msg := nl.NewIfAddrmsg(family) - msg.Index = uint32(base.Index) - prefixlen, _ := addr.Mask.Size() - msg.Prefixlen = uint8(prefixlen) - req.AddData(msg) - - var addrData []byte - if family == FAMILY_V4 { - addrData = addr.IP.To4() - } else { - addrData = addr.IP.To16() - } - - localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData) - req.AddData(localData) - - addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData) - req.AddData(addressData) - - if addr.Label != "" { - labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label)) - req.AddData(labelData) - } - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// AddrList gets a list of IP addresses in the system. -// Equivalent to: `ip addr show`. -// The list can be filtered by link and ip family. -func AddrList(link Link, family int) ([]Addr, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) - msg := nl.NewIfInfomsg(family) - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR) - if err != nil { - return nil, err - } - - index := 0 - if link != nil { - base := link.Attrs() - ensureIndex(base) - index = base.Index - } - - var res []Addr - for _, m := range msgs { - msg := nl.DeserializeIfAddrmsg(m) - - if link != nil && msg.Index != uint32(index) { - // Ignore messages from other interfaces - continue - } - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - var local, dst *net.IPNet - var addr Addr - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.IFA_ADDRESS: - dst = &net.IPNet{ - IP: attr.Value, - Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), - } - case syscall.IFA_LOCAL: - local = &net.IPNet{ - IP: attr.Value, - Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), - } - case syscall.IFA_LABEL: - addr.Label = string(attr.Value[:len(attr.Value)-1]) - } - } - - // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS - if local != nil { - addr.IPNet = local - } else { - addr.IPNet = dst - } - - res = append(res, addr) - } - - return res, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go deleted file mode 100644 index 83ad7007b99d20815d41e4efc4a17889624c12d3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go +++ /dev/null @@ -1,55 +0,0 @@ -package netlink - -import ( - "fmt" -) - -type Filter interface { - Attrs() *FilterAttrs - Type() string -} - -// Filter represents a netlink filter. A filter is associated with a link, -// has a handle and a parent. The root filter of a device should have a -// parent == HANDLE_ROOT. -type FilterAttrs struct { - LinkIndex int - Handle uint32 - Parent uint32 - Priority uint16 // lower is higher priority - Protocol uint16 // syscall.ETH_P_* -} - -func (q FilterAttrs) String() string { - return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol) -} - -// U32 filters on many packet related properties -type U32 struct { - FilterAttrs - // Currently only supports redirecting to another interface - RedirIndex int -} - -func (filter *U32) Attrs() *FilterAttrs { - return &filter.FilterAttrs -} - -func (filter *U32) Type() string { - return "u32" -} - -// GenericFilter filters represent types that are not currently understood -// by this netlink library. -type GenericFilter struct { - FilterAttrs - FilterType string -} - -func (filter *GenericFilter) Attrs() *FilterAttrs { - return &filter.FilterAttrs -} - -func (filter *GenericFilter) Type() string { - return filter.FilterType -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go deleted file mode 100644 index 1ec69870280554c87df6181eb358f171ac698925..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go +++ /dev/null @@ -1,191 +0,0 @@ -package netlink - -import ( - "fmt" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -// FilterDel will delete a filter from the system. -// Equivalent to: `tc filter del $filter` -func FilterDel(filter Filter) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK) - base := filter.Attrs() - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Ifindex: int32(base.LinkIndex), - Handle: base.Handle, - Parent: base.Parent, - Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), - } - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// FilterAdd will add a filter to the system. -// Equivalent to: `tc filter add $filter` -func FilterAdd(filter Filter) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - base := filter.Attrs() - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Ifindex: int32(base.LinkIndex), - Handle: base.Handle, - Parent: base.Parent, - Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), - } - req.AddData(msg) - req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type()))) - - options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) - if u32, ok := filter.(*U32); ok { - // match all - sel := nl.TcU32Sel{ - Nkeys: 1, - Flags: nl.TC_U32_TERMINAL, - } - sel.Keys = append(sel.Keys, nl.TcU32Key{}) - nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize()) - actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) - table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil) - nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred")) - // redirect to other interface - mir := nl.TcMirred{ - Action: nl.TC_ACT_STOLEN, - Eaction: nl.TCA_EGRESS_REDIR, - Ifindex: uint32(u32.RedirIndex), - } - aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil) - nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize()) - } - req.AddData(options) - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// FilterList gets a list of filters in the system. -// Equivalent to: `tc filter show`. -// Generally retunrs nothing if link and parent are not specified. -func FilterList(link Link, parent uint32) ([]Filter, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Parent: parent, - } - if link != nil { - base := link.Attrs() - ensureIndex(base) - msg.Ifindex = int32(base.Index) - } - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER) - if err != nil { - return nil, err - } - - var res []Filter - for _, m := range msgs { - msg := nl.DeserializeTcMsg(m) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - base := FilterAttrs{ - LinkIndex: int(msg.Ifindex), - Handle: msg.Handle, - Parent: msg.Parent, - } - base.Priority, base.Protocol = MajorMinor(msg.Info) - base.Protocol = nl.Swap16(base.Protocol) - - var filter Filter - filterType := "" - detailed := false - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.TCA_KIND: - filterType = string(attr.Value[:len(attr.Value)-1]) - switch filterType { - case "u32": - filter = &U32{} - default: - filter = &GenericFilter{FilterType: filterType} - } - case nl.TCA_OPTIONS: - switch filterType { - case "u32": - data, err := nl.ParseRouteAttr(attr.Value) - if err != nil { - return nil, err - } - detailed, err = parseU32Data(filter, data) - if err != nil { - return nil, err - } - } - } - } - // only return the detailed version of the filter - if detailed { - *filter.Attrs() = base - res = append(res, filter) - } - } - - return res, nil -} - -func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { - native = nl.NativeEndian() - u32 := filter.(*U32) - detailed := false - for _, datum := range data { - switch datum.Attr.Type { - case nl.TCA_U32_SEL: - detailed = true - sel := nl.DeserializeTcU32Sel(datum.Value) - // only parse if we have a very basic redirect - if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 { - return detailed, nil - } - case nl.TCA_U32_ACT: - table, err := nl.ParseRouteAttr(datum.Value) - if err != nil { - return detailed, err - } - if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB { - return detailed, fmt.Errorf("Action table not formed properly") - } - aattrs, err := nl.ParseRouteAttr(table[0].Value) - for _, aattr := range aattrs { - switch aattr.Attr.Type { - case nl.TCA_KIND: - actionType := string(aattr.Value[:len(aattr.Value)-1]) - // only parse if the action is mirred - if actionType != "mirred" { - return detailed, nil - } - case nl.TCA_OPTIONS: - adata, err := nl.ParseRouteAttr(aattr.Value) - if err != nil { - return detailed, err - } - for _, adatum := range adata { - switch adatum.Attr.Type { - case nl.TCA_MIRRED_PARMS: - mir := nl.DeserializeTcMirred(adatum.Value) - u32.RedirIndex = int(mir.Ifindex) - } - } - } - } - } - } - return detailed, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go deleted file mode 100644 index 18fd1759adb5e6e87edee57b307f64a720af4802..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go +++ /dev/null @@ -1,223 +0,0 @@ -package netlink - -import "net" - -// Link represents a link device from netlink. Shared link attributes -// like name may be retrieved using the Attrs() method. Unique data -// can be retrieved by casting the object to the proper type. -type Link interface { - Attrs() *LinkAttrs - Type() string -} - -type ( - NsPid int - NsFd int -) - -// LinkAttrs represents data shared by most link types -type LinkAttrs struct { - Index int - MTU int - TxQLen int // Transmit Queue Length - Name string - HardwareAddr net.HardwareAddr - Flags net.Flags - ParentIndex int // index of the parent link device - MasterIndex int // must be the index of a bridge - Namespace interface{} // nil | NsPid | NsFd -} - -// NewLinkAttrs returns LinkAttrs structure filled with default values -func NewLinkAttrs() LinkAttrs { - return LinkAttrs{ - TxQLen: -1, - } -} - -// Device links cannot be created via netlink. These links -// are links created by udev like 'lo' and 'etho0' -type Device struct { - LinkAttrs -} - -func (device *Device) Attrs() *LinkAttrs { - return &device.LinkAttrs -} - -func (device *Device) Type() string { - return "device" -} - -// Dummy links are dummy ethernet devices -type Dummy struct { - LinkAttrs -} - -func (dummy *Dummy) Attrs() *LinkAttrs { - return &dummy.LinkAttrs -} - -func (dummy *Dummy) Type() string { - return "dummy" -} - -// Ifb links are advanced dummy devices for packet filtering -type Ifb struct { - LinkAttrs -} - -func (ifb *Ifb) Attrs() *LinkAttrs { - return &ifb.LinkAttrs -} - -func (ifb *Ifb) Type() string { - return "ifb" -} - -// Bridge links are simple linux bridges -type Bridge struct { - LinkAttrs -} - -func (bridge *Bridge) Attrs() *LinkAttrs { - return &bridge.LinkAttrs -} - -func (bridge *Bridge) Type() string { - return "bridge" -} - -// Vlan links have ParentIndex set in their Attrs() -type Vlan struct { - LinkAttrs - VlanId int -} - -func (vlan *Vlan) Attrs() *LinkAttrs { - return &vlan.LinkAttrs -} - -func (vlan *Vlan) Type() string { - return "vlan" -} - -type MacvlanMode uint16 - -const ( - MACVLAN_MODE_DEFAULT MacvlanMode = iota - MACVLAN_MODE_PRIVATE - MACVLAN_MODE_VEPA - MACVLAN_MODE_BRIDGE - MACVLAN_MODE_PASSTHRU - MACVLAN_MODE_SOURCE -) - -// Macvlan links have ParentIndex set in their Attrs() -type Macvlan struct { - LinkAttrs - Mode MacvlanMode -} - -func (macvlan *Macvlan) Attrs() *LinkAttrs { - return &macvlan.LinkAttrs -} - -func (macvlan *Macvlan) Type() string { - return "macvlan" -} - -// Macvtap - macvtap is a virtual interfaces based on macvlan -type Macvtap struct { - Macvlan -} - -func (macvtap Macvtap) Type() string { - return "macvtap" -} - -// Veth devices must specify PeerName on create -type Veth struct { - LinkAttrs - PeerName string // veth on create only -} - -func (veth *Veth) Attrs() *LinkAttrs { - return &veth.LinkAttrs -} - -func (veth *Veth) Type() string { - return "veth" -} - -// GenericLink links represent types that are not currently understood -// by this netlink library. -type GenericLink struct { - LinkAttrs - LinkType string -} - -func (generic *GenericLink) Attrs() *LinkAttrs { - return &generic.LinkAttrs -} - -func (generic *GenericLink) Type() string { - return generic.LinkType -} - -type Vxlan struct { - LinkAttrs - VxlanId int - VtepDevIndex int - SrcAddr net.IP - Group net.IP - TTL int - TOS int - Learning bool - Proxy bool - RSC bool - L2miss bool - L3miss bool - NoAge bool - GBP bool - Age int - Limit int - Port int - PortLow int - PortHigh int -} - -func (vxlan *Vxlan) Attrs() *LinkAttrs { - return &vxlan.LinkAttrs -} - -func (vxlan *Vxlan) Type() string { - return "vxlan" -} - -type IPVlanMode uint16 - -const ( - IPVLAN_MODE_L2 IPVlanMode = iota - IPVLAN_MODE_L3 - IPVLAN_MODE_MAX -) - -type IPVlan struct { - LinkAttrs - Mode IPVlanMode -} - -func (ipvlan *IPVlan) Attrs() *LinkAttrs { - return &ipvlan.LinkAttrs -} - -func (ipvlan *IPVlan) Type() string { - return "ipvlan" -} - -// iproute2 supported devices; -// vlan | veth | vcan | dummy | ifb | macvlan | macvtap | -// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | -// gre | gretap | ip6gre | ip6gretap | vti | nlmon | -// bond_slave | ipvlan diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go deleted file mode 100644 index 6851150443b48310c6015edacb368f1e01c09392..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go +++ /dev/null @@ -1,750 +0,0 @@ -package netlink - -import ( - "bytes" - "encoding/binary" - "fmt" - "net" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -var native = nl.NativeEndian() -var lookupByDump = false - -var macvlanModes = [...]uint32{ - 0, - nl.MACVLAN_MODE_PRIVATE, - nl.MACVLAN_MODE_VEPA, - nl.MACVLAN_MODE_BRIDGE, - nl.MACVLAN_MODE_PASSTHRU, - nl.MACVLAN_MODE_SOURCE, -} - -func ensureIndex(link *LinkAttrs) { - if link != nil && link.Index == 0 { - newlink, _ := LinkByName(link.Name) - if newlink != nil { - link.Index = newlink.Attrs().Index - } - } -} - -// LinkSetUp enables the link device. -// Equivalent to: `ip link set $link up` -func LinkSetUp(link Link) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Change = syscall.IFF_UP - msg.Flags = syscall.IFF_UP - msg.Index = int32(base.Index) - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetDown disables link device. -// Equivalent to: `ip link set $link down` -func LinkSetDown(link Link) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Change = syscall.IFF_UP - msg.Flags = 0 & ^syscall.IFF_UP - msg.Index = int32(base.Index) - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetMTU sets the mtu of the link device. -// Equivalent to: `ip link set $link mtu $mtu` -func LinkSetMTU(link Link, mtu int) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - b := make([]byte, 4) - native.PutUint32(b, uint32(mtu)) - - data := nl.NewRtAttr(syscall.IFLA_MTU, b) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetName sets the name of the link device. -// Equivalent to: `ip link set $link name $name` -func LinkSetName(link Link, name string) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name)) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetHardwareAddr sets the hardware address of the link device. -// Equivalent to: `ip link set $link address $hwaddr` -func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr)) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetMaster sets the master of the link device. -// Equivalent to: `ip link set $link master $master` -func LinkSetMaster(link Link, master *Bridge) error { - index := 0 - if master != nil { - masterBase := master.Attrs() - ensureIndex(masterBase) - index = masterBase.Index - } - return LinkSetMasterByIndex(link, index) -} - -// LinkSetMasterByIndex sets the master of the link device. -// Equivalent to: `ip link set $link master $master` -func LinkSetMasterByIndex(link Link, masterIndex int) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - b := make([]byte, 4) - native.PutUint32(b, uint32(masterIndex)) - - data := nl.NewRtAttr(syscall.IFLA_MASTER, b) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetNsPid puts the device into a new network namespace. The -// pid must be a pid of a running process. -// Equivalent to: `ip link set $link netns $pid` -func LinkSetNsPid(link Link, nspid int) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - b := make([]byte, 4) - native.PutUint32(b, uint32(nspid)) - - data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// LinkSetNsFd puts the device into a new network namespace. The -// fd must be an open file descriptor to a network namespace. -// Similar to: `ip link set $link netns $ns` -func LinkSetNsFd(link Link, fd int) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - b := make([]byte, 4) - native.PutUint32(b, uint32(fd)) - - data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b) - req.AddData(data) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -func boolAttr(val bool) []byte { - var v uint8 - if val { - v = 1 - } - return nl.Uint8Attr(v) -} - -type vxlanPortRange struct { - Lo, Hi uint16 -} - -func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId))) - if vxlan.VtepDevIndex != 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex))) - } - if vxlan.SrcAddr != nil { - ip := vxlan.SrcAddr.To4() - if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL, []byte(ip)) - } else { - ip = vxlan.SrcAddr.To16() - if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL6, []byte(ip)) - } - } - } - if vxlan.Group != nil { - group := vxlan.Group.To4() - if group != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP, []byte(group)) - } else { - group = vxlan.Group.To16() - if group != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP6, []byte(group)) - } - } - } - - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL))) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS))) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss)) - - if vxlan.GBP { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP)) - } - - if vxlan.NoAge { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0)) - } else if vxlan.Age > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age))) - } - if vxlan.Limit > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit))) - } - if vxlan.Port > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, nl.Uint16Attr(uint16(vxlan.Port))) - } - if vxlan.PortLow > 0 || vxlan.PortHigh > 0 { - pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)} - - buf := new(bytes.Buffer) - binary.Write(buf, binary.BigEndian, &pr) - - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes()) - } -} - -// LinkAdd adds a new link device. The type and features of the device -// are taken fromt the parameters in the link object. -// Equivalent to: `ip link add $link` -func LinkAdd(link Link) error { - // TODO: set mtu and hardware address - // TODO: support extra data for macvlan - base := link.Attrs() - - if base.Name == "" { - return fmt.Errorf("LinkAttrs.Name cannot be empty!") - } - - req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - req.AddData(msg) - - if base.ParentIndex != 0 { - b := make([]byte, 4) - native.PutUint32(b, uint32(base.ParentIndex)) - data := nl.NewRtAttr(syscall.IFLA_LINK, b) - req.AddData(data) - } else if link.Type() == "ipvlan" { - return fmt.Errorf("Can't create ipvlan link without ParentIndex") - } - - nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name)) - req.AddData(nameData) - - if base.MTU > 0 { - mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) - req.AddData(mtu) - } - - if base.TxQLen >= 0 { - qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) - req.AddData(qlen) - } - - if base.Namespace != nil { - var attr *nl.RtAttr - switch base.Namespace.(type) { - case NsPid: - val := nl.Uint32Attr(uint32(base.Namespace.(NsPid))) - attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val) - case NsFd: - val := nl.Uint32Attr(uint32(base.Namespace.(NsFd))) - attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val) - } - - req.AddData(attr) - } - - linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil) - nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) - - if vlan, ok := link.(*Vlan); ok { - b := make([]byte, 2) - native.PutUint16(b, uint16(vlan.VlanId)) - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b) - } else if veth, ok := link.(*Veth); ok { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil) - nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC) - nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName)) - if base.TxQLen >= 0 { - nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) - } - if base.MTU > 0 { - nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) - } - - } else if vxlan, ok := link.(*Vxlan); ok { - addVxlanAttrs(vxlan, linkInfo) - } else if ipv, ok := link.(*IPVlan); ok { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode))) - } else if macv, ok := link.(*Macvlan); ok { - if macv.Mode != MACVLAN_MODE_DEFAULT { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode])) - } - } - - req.AddData(linkInfo) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - if err != nil { - return err - } - - ensureIndex(base) - - // can't set master during create, so set it afterwards - if base.MasterIndex != 0 { - // TODO: verify MasterIndex is actually a bridge? - return LinkSetMasterByIndex(link, base.MasterIndex) - } - return nil -} - -// LinkDel deletes link device. Either Index or Name must be set in -// the link object for it to be deleted. The other values are ignored. -// Equivalent to: `ip link del $link` -func LinkDel(link Link) error { - base := link.Attrs() - - ensureIndex(base) - - req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(base.Index) - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -func linkByNameDump(name string) (Link, error) { - links, err := LinkList() - if err != nil { - return nil, err - } - - for _, link := range links { - if link.Attrs().Name == name { - return link, nil - } - } - return nil, fmt.Errorf("Link %s not found", name) -} - -// LinkByName finds a link by name and returns a pointer to the object. -func LinkByName(name string) (Link, error) { - if lookupByDump { - return linkByNameDump(name) - } - - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - req.AddData(msg) - - nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name)) - req.AddData(nameData) - - link, err := execGetLink(req) - if err == syscall.EINVAL { - // older kernels don't support looking up via IFLA_IFNAME - // so fall back to dumping all links - lookupByDump = true - return linkByNameDump(name) - } - - return link, err -} - -// LinkByIndex finds a link by index and returns a pointer to the object. -func LinkByIndex(index int) (Link, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - msg.Index = int32(index) - req.AddData(msg) - - return execGetLink(req) -} - -func execGetLink(req *nl.NetlinkRequest) (Link, error) { - msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0) - if err != nil { - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.ENODEV { - return nil, fmt.Errorf("Link not found") - } - } - return nil, err - } - - switch { - case len(msgs) == 0: - return nil, fmt.Errorf("Link not found") - - case len(msgs) == 1: - return linkDeserialize(msgs[0]) - - default: - return nil, fmt.Errorf("More than one link found") - } -} - -// linkDeserialize deserializes a raw message received from netlink into -// a link object. -func linkDeserialize(m []byte) (Link, error) { - msg := nl.DeserializeIfInfomsg(m) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)} - var link Link - linkType := "" - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.IFLA_LINKINFO: - infos, err := nl.ParseRouteAttr(attr.Value) - if err != nil { - return nil, err - } - for _, info := range infos { - switch info.Attr.Type { - case nl.IFLA_INFO_KIND: - linkType = string(info.Value[:len(info.Value)-1]) - switch linkType { - case "dummy": - link = &Dummy{} - case "ifb": - link = &Ifb{} - case "bridge": - link = &Bridge{} - case "vlan": - link = &Vlan{} - case "veth": - link = &Veth{} - case "vxlan": - link = &Vxlan{} - case "ipvlan": - link = &IPVlan{} - case "macvlan": - link = &Macvlan{} - case "macvtap": - link = &Macvtap{} - default: - link = &GenericLink{LinkType: linkType} - } - case nl.IFLA_INFO_DATA: - data, err := nl.ParseRouteAttr(info.Value) - if err != nil { - return nil, err - } - switch linkType { - case "vlan": - parseVlanData(link, data) - case "vxlan": - parseVxlanData(link, data) - case "ipvlan": - parseIPVlanData(link, data) - case "macvlan": - parseMacvlanData(link, data) - case "macvtap": - parseMacvtapData(link, data) - } - } - } - case syscall.IFLA_ADDRESS: - var nonzero bool - for _, b := range attr.Value { - if b != 0 { - nonzero = true - } - } - if nonzero { - base.HardwareAddr = attr.Value[:] - } - case syscall.IFLA_IFNAME: - base.Name = string(attr.Value[:len(attr.Value)-1]) - case syscall.IFLA_MTU: - base.MTU = int(native.Uint32(attr.Value[0:4])) - case syscall.IFLA_LINK: - base.ParentIndex = int(native.Uint32(attr.Value[0:4])) - case syscall.IFLA_MASTER: - base.MasterIndex = int(native.Uint32(attr.Value[0:4])) - case syscall.IFLA_TXQLEN: - base.TxQLen = int(native.Uint32(attr.Value[0:4])) - } - } - // Links that don't have IFLA_INFO_KIND are hardware devices - if link == nil { - link = &Device{} - } - *link.Attrs() = base - - return link, nil -} - -// LinkList gets a list of link devices. -// Equivalent to: `ip link show` -func LinkList() ([]Link, error) { - // NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need - // to get the message ourselves to parse link type. - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) - - msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK) - if err != nil { - return nil, err - } - - var res []Link - for _, m := range msgs { - link, err := linkDeserialize(m) - if err != nil { - return nil, err - } - res = append(res, link) - } - - return res, nil -} - -func LinkSetHairpin(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE) -} - -func LinkSetGuard(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) -} - -func LinkSetFastLeave(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE) -} - -func LinkSetLearning(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING) -} - -func LinkSetRootBlock(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT) -} - -func LinkSetFlood(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) -} - -func setProtinfoAttr(link Link, mode bool, attr int) error { - base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) - msg.Index = int32(base.Index) - req.AddData(msg) - - br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil) - nl.NewRtAttrChild(br, attr, boolToByte(mode)) - req.AddData(br) - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - if err != nil { - return err - } - return nil -} - -func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) { - vlan := link.(*Vlan) - for _, datum := range data { - switch datum.Attr.Type { - case nl.IFLA_VLAN_ID: - vlan.VlanId = int(native.Uint16(datum.Value[0:2])) - } - } -} - -func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) { - vxlan := link.(*Vxlan) - for _, datum := range data { - switch datum.Attr.Type { - case nl.IFLA_VXLAN_ID: - vxlan.VxlanId = int(native.Uint32(datum.Value[0:4])) - case nl.IFLA_VXLAN_LINK: - vxlan.VtepDevIndex = int(native.Uint32(datum.Value[0:4])) - case nl.IFLA_VXLAN_LOCAL: - vxlan.SrcAddr = net.IP(datum.Value[0:4]) - case nl.IFLA_VXLAN_LOCAL6: - vxlan.SrcAddr = net.IP(datum.Value[0:16]) - case nl.IFLA_VXLAN_GROUP: - vxlan.Group = net.IP(datum.Value[0:4]) - case nl.IFLA_VXLAN_GROUP6: - vxlan.Group = net.IP(datum.Value[0:16]) - case nl.IFLA_VXLAN_TTL: - vxlan.TTL = int(datum.Value[0]) - case nl.IFLA_VXLAN_TOS: - vxlan.TOS = int(datum.Value[0]) - case nl.IFLA_VXLAN_LEARNING: - vxlan.Learning = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_PROXY: - vxlan.Proxy = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_RSC: - vxlan.RSC = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_L2MISS: - vxlan.L2miss = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_L3MISS: - vxlan.L3miss = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_GBP: - vxlan.GBP = int8(datum.Value[0]) != 0 - case nl.IFLA_VXLAN_AGEING: - vxlan.Age = int(native.Uint32(datum.Value[0:4])) - vxlan.NoAge = vxlan.Age == 0 - case nl.IFLA_VXLAN_LIMIT: - vxlan.Limit = int(native.Uint32(datum.Value[0:4])) - case nl.IFLA_VXLAN_PORT: - vxlan.Port = int(native.Uint16(datum.Value[0:2])) - case nl.IFLA_VXLAN_PORT_RANGE: - buf := bytes.NewBuffer(datum.Value[0:4]) - var pr vxlanPortRange - if binary.Read(buf, binary.BigEndian, &pr) != nil { - vxlan.PortLow = int(pr.Lo) - vxlan.PortHigh = int(pr.Hi) - } - } - } -} - -func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) { - ipv := link.(*IPVlan) - for _, datum := range data { - if datum.Attr.Type == nl.IFLA_IPVLAN_MODE { - ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4])) - return - } - } -} - -func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) { - macv := link.(*Macvtap) - parseMacvlanData(&macv.Macvlan, data) -} - -func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) { - macv := link.(*Macvlan) - for _, datum := range data { - if datum.Attr.Type == nl.IFLA_MACVLAN_MODE { - switch native.Uint32(datum.Value[0:4]) { - case nl.MACVLAN_MODE_PRIVATE: - macv.Mode = MACVLAN_MODE_PRIVATE - case nl.MACVLAN_MODE_VEPA: - macv.Mode = MACVLAN_MODE_VEPA - case nl.MACVLAN_MODE_BRIDGE: - macv.Mode = MACVLAN_MODE_BRIDGE - case nl.MACVLAN_MODE_PASSTHRU: - macv.Mode = MACVLAN_MODE_PASSTHRU - case nl.MACVLAN_MODE_SOURCE: - macv.Mode = MACVLAN_MODE_SOURCE - } - return - } - } -} - -// copied from pkg/net_linux.go -func linkFlags(rawFlags uint32) net.Flags { - var f net.Flags - if rawFlags&syscall.IFF_UP != 0 { - f |= net.FlagUp - } - if rawFlags&syscall.IFF_BROADCAST != 0 { - f |= net.FlagBroadcast - } - if rawFlags&syscall.IFF_LOOPBACK != 0 { - f |= net.FlagLoopback - } - if rawFlags&syscall.IFF_POINTOPOINT != 0 { - f |= net.FlagPointToPoint - } - if rawFlags&syscall.IFF_MULTICAST != 0 { - f |= net.FlagMulticast - } - return f -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go deleted file mode 100644 index 0e5eb90c9ebe0743f0082250d7efa2889b0593e7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go +++ /dev/null @@ -1,22 +0,0 @@ -package netlink - -import ( - "fmt" - "net" -) - -// Neigh represents a link layer neighbor from netlink. -type Neigh struct { - LinkIndex int - Family int - State int - Type int - Flags int - IP net.IP - HardwareAddr net.HardwareAddr -} - -// String returns $ip/$hwaddr $label -func (neigh *Neigh) String() string { - return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go deleted file mode 100644 index 620a0ee708845e2fb05e9c7375c529d803472075..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go +++ /dev/null @@ -1,189 +0,0 @@ -package netlink - -import ( - "net" - "syscall" - "unsafe" - - "github.com/vishvananda/netlink/nl" -) - -const ( - NDA_UNSPEC = iota - NDA_DST - NDA_LLADDR - NDA_CACHEINFO - NDA_PROBES - NDA_VLAN - NDA_PORT - NDA_VNI - NDA_IFINDEX - NDA_MAX = NDA_IFINDEX -) - -// Neighbor Cache Entry States. -const ( - NUD_NONE = 0x00 - NUD_INCOMPLETE = 0x01 - NUD_REACHABLE = 0x02 - NUD_STALE = 0x04 - NUD_DELAY = 0x08 - NUD_PROBE = 0x10 - NUD_FAILED = 0x20 - NUD_NOARP = 0x40 - NUD_PERMANENT = 0x80 -) - -// Neighbor Flags -const ( - NTF_USE = 0x01 - NTF_SELF = 0x02 - NTF_MASTER = 0x04 - NTF_PROXY = 0x08 - NTF_ROUTER = 0x80 -) - -type Ndmsg struct { - Family uint8 - Index uint32 - State uint16 - Flags uint8 - Type uint8 -} - -func deserializeNdmsg(b []byte) *Ndmsg { - var dummy Ndmsg - return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0])) -} - -func (msg *Ndmsg) Serialize() []byte { - return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:] -} - -func (msg *Ndmsg) Len() int { - return int(unsafe.Sizeof(*msg)) -} - -// NeighAdd will add an IP to MAC mapping to the ARP table -// Equivalent to: `ip neigh add ....` -func NeighAdd(neigh *Neigh) error { - return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL) -} - -// NeighAdd will add or replace an IP to MAC mapping to the ARP table -// Equivalent to: `ip neigh replace....` -func NeighSet(neigh *Neigh) error { - return neighAdd(neigh, syscall.NLM_F_CREATE) -} - -// NeighAppend will append an entry to FDB -// Equivalent to: `bridge fdb append...` -func NeighAppend(neigh *Neigh) error { - return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND) -} - -func neighAdd(neigh *Neigh, mode int) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK) - return neighHandle(neigh, req) -} - -// NeighDel will delete an IP address from a link device. -// Equivalent to: `ip addr del $addr dev $link` -func NeighDel(neigh *Neigh) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK) - return neighHandle(neigh, req) -} - -func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error { - var family int - if neigh.Family > 0 { - family = neigh.Family - } else { - family = nl.GetIPFamily(neigh.IP) - } - - msg := Ndmsg{ - Family: uint8(family), - Index: uint32(neigh.LinkIndex), - State: uint16(neigh.State), - Type: uint8(neigh.Type), - Flags: uint8(neigh.Flags), - } - req.AddData(&msg) - - ipData := neigh.IP.To4() - if ipData == nil { - ipData = neigh.IP.To16() - } - - dstData := nl.NewRtAttr(NDA_DST, ipData) - req.AddData(dstData) - - hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr)) - req.AddData(hwData) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// NeighList gets a list of IP-MAC mappings in the system (ARP table). -// Equivalent to: `ip neighbor show`. -// The list can be filtered by link and ip family. -func NeighList(linkIndex, family int) ([]Neigh, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP) - msg := Ndmsg{ - Family: uint8(family), - } - req.AddData(&msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH) - if err != nil { - return nil, err - } - - var res []Neigh - for _, m := range msgs { - ndm := deserializeNdmsg(m) - if linkIndex != 0 && int(ndm.Index) != linkIndex { - // Ignore messages from other interfaces - continue - } - - neigh, err := NeighDeserialize(m) - if err != nil { - continue - } - - res = append(res, *neigh) - } - - return res, nil -} - -func NeighDeserialize(m []byte) (*Neigh, error) { - msg := deserializeNdmsg(m) - - neigh := Neigh{ - LinkIndex: int(msg.Index), - Family: int(msg.Family), - State: int(msg.State), - Type: int(msg.Type), - Flags: int(msg.Flags), - } - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - for _, attr := range attrs { - switch attr.Attr.Type { - case NDA_DST: - neigh.IP = net.IP(attr.Value) - case NDA_LLADDR: - neigh.HardwareAddr = net.HardwareAddr(attr.Value) - } - } - - return &neigh, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go deleted file mode 100644 index 41ebdb11f1c17626f0ac85b4816ddd7d33407933..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go +++ /dev/null @@ -1,39 +0,0 @@ -// Package netlink provides a simple library for netlink. Netlink is -// the interface a user-space program in linux uses to communicate with -// the kernel. It can be used to add and remove interfaces, set up ip -// addresses and routes, and confiugre ipsec. Netlink communication -// requires elevated privileges, so in most cases this code needs to -// be run as root. The low level primitives for netlink are contained -// in the nl subpackage. This package attempts to provide a high-level -// interface that is loosly modeled on the iproute2 cli. -package netlink - -import ( - "net" - - "github.com/vishvananda/netlink/nl" -) - -const ( - // Family type definitions - FAMILY_ALL = nl.FAMILY_ALL - FAMILY_V4 = nl.FAMILY_V4 - FAMILY_V6 = nl.FAMILY_V6 -) - -// ParseIPNet parses a string in ip/net format and returns a net.IPNet. -// This is valuable because addresses in netlink are often IPNets and -// ParseCIDR returns an IPNet with the IP part set to the base IP of the -// range. -func ParseIPNet(s string) (*net.IPNet, error) { - ip, ipNet, err := net.ParseCIDR(s) - if err != nil { - return nil, err - } - return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil -} - -// NewIPNet generates an IPNet from an ip address using a netmask of 32. -func NewIPNet(ip net.IP) *net.IPNet { - return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)} -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go deleted file mode 100644 index 10c49c1bfce8fa9cc88c1ce1bfcde65e17cdae52..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go +++ /dev/null @@ -1,143 +0,0 @@ -// +build !linux - -package netlink - -import ( - "errors" -) - -var ( - ErrNotImplemented = errors.New("not implemented") -) - -func LinkSetUp(link *Link) error { - return ErrNotImplemented -} - -func LinkSetDown(link *Link) error { - return ErrNotImplemented -} - -func LinkSetMTU(link *Link, mtu int) error { - return ErrNotImplemented -} - -func LinkSetMaster(link *Link, master *Link) error { - return ErrNotImplemented -} - -func LinkSetNsPid(link *Link, nspid int) error { - return ErrNotImplemented -} - -func LinkSetNsFd(link *Link, fd int) error { - return ErrNotImplemented -} - -func LinkAdd(link *Link) error { - return ErrNotImplemented -} - -func LinkDel(link *Link) error { - return ErrNotImplemented -} - -func SetHairpin(link Link, mode bool) error { - return ErrNotImplemented -} - -func SetGuard(link Link, mode bool) error { - return ErrNotImplemented -} - -func SetFastLeave(link Link, mode bool) error { - return ErrNotImplemented -} - -func SetLearning(link Link, mode bool) error { - return ErrNotImplemented -} - -func SetRootBlock(link Link, mode bool) error { - return ErrNotImplemented -} - -func SetFlood(link Link, mode bool) error { - return ErrNotImplemented -} - -func LinkList() ([]Link, error) { - return nil, ErrNotImplemented -} - -func AddrAdd(link *Link, addr *Addr) error { - return ErrNotImplemented -} - -func AddrDel(link *Link, addr *Addr) error { - return ErrNotImplemented -} - -func AddrList(link *Link, family int) ([]Addr, error) { - return nil, ErrNotImplemented -} - -func RouteAdd(route *Route) error { - return ErrNotImplemented -} - -func RouteDel(route *Route) error { - return ErrNotImplemented -} - -func RouteList(link *Link, family int) ([]Route, error) { - return nil, ErrNotImplemented -} - -func XfrmPolicyAdd(policy *XfrmPolicy) error { - return ErrNotImplemented -} - -func XfrmPolicyDel(policy *XfrmPolicy) error { - return ErrNotImplemented -} - -func XfrmPolicyList(family int) ([]XfrmPolicy, error) { - return nil, ErrNotImplemented -} - -func XfrmStateAdd(policy *XfrmState) error { - return ErrNotImplemented -} - -func XfrmStateDel(policy *XfrmState) error { - return ErrNotImplemented -} - -func XfrmStateList(family int) ([]XfrmState, error) { - return nil, ErrNotImplemented -} - -func NeighAdd(neigh *Neigh) error { - return ErrNotImplemented -} - -func NeighSet(neigh *Neigh) error { - return ErrNotImplemented -} - -func NeighAppend(neigh *Neigh) error { - return ErrNotImplemented -} - -func NeighDel(neigh *Neigh) error { - return ErrNotImplemented -} - -func NeighList(linkIndex, family int) ([]Neigh, error) { - return nil, ErrNotImplemented -} - -func NeighDeserialize(m []byte) (*Ndmsg, *Neigh, error) { - return nil, nil, ErrNotImplemented -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go deleted file mode 100644 index 17088fa0c0a1b699f4ccb076f215bfaaa97d0cd8..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go +++ /dev/null @@ -1,47 +0,0 @@ -package nl - -import ( - "syscall" - "unsafe" -) - -type IfAddrmsg struct { - syscall.IfAddrmsg -} - -func NewIfAddrmsg(family int) *IfAddrmsg { - return &IfAddrmsg{ - IfAddrmsg: syscall.IfAddrmsg{ - Family: uint8(family), - }, - } -} - -// struct ifaddrmsg { -// __u8 ifa_family; -// __u8 ifa_prefixlen; /* The prefix length */ -// __u8 ifa_flags; /* Flags */ -// __u8 ifa_scope; /* Address scope */ -// __u32 ifa_index; /* Link index */ -// }; - -// type IfAddrmsg struct { -// Family uint8 -// Prefixlen uint8 -// Flags uint8 -// Scope uint8 -// Index uint32 -// } -// SizeofIfAddrmsg = 0x8 - -func DeserializeIfAddrmsg(b []byte) *IfAddrmsg { - return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0])) -} - -func (msg *IfAddrmsg) Serialize() []byte { - return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:] -} - -func (msg *IfAddrmsg) Len() int { - return syscall.SizeofIfAddrmsg -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go deleted file mode 100644 index 1f9ab088f0f3dad9cfd6d60d21404c1d813a9070..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go +++ /dev/null @@ -1,104 +0,0 @@ -package nl - -const ( - DEFAULT_CHANGE = 0xFFFFFFFF -) - -const ( - IFLA_INFO_UNSPEC = iota - IFLA_INFO_KIND - IFLA_INFO_DATA - IFLA_INFO_XSTATS - IFLA_INFO_MAX = IFLA_INFO_XSTATS -) - -const ( - IFLA_VLAN_UNSPEC = iota - IFLA_VLAN_ID - IFLA_VLAN_FLAGS - IFLA_VLAN_EGRESS_QOS - IFLA_VLAN_INGRESS_QOS - IFLA_VLAN_PROTOCOL - IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL -) - -const ( - VETH_INFO_UNSPEC = iota - VETH_INFO_PEER - VETH_INFO_MAX = VETH_INFO_PEER -) - -const ( - IFLA_VXLAN_UNSPEC = iota - IFLA_VXLAN_ID - IFLA_VXLAN_GROUP - IFLA_VXLAN_LINK - IFLA_VXLAN_LOCAL - IFLA_VXLAN_TTL - IFLA_VXLAN_TOS - IFLA_VXLAN_LEARNING - IFLA_VXLAN_AGEING - IFLA_VXLAN_LIMIT - IFLA_VXLAN_PORT_RANGE - IFLA_VXLAN_PROXY - IFLA_VXLAN_RSC - IFLA_VXLAN_L2MISS - IFLA_VXLAN_L3MISS - IFLA_VXLAN_PORT - IFLA_VXLAN_GROUP6 - IFLA_VXLAN_LOCAL6 - IFLA_VXLAN_UDP_CSUM - IFLA_VXLAN_UDP_ZERO_CSUM6_TX - IFLA_VXLAN_UDP_ZERO_CSUM6_RX - IFLA_VXLAN_REMCSUM_TX - IFLA_VXLAN_REMCSUM_RX - IFLA_VXLAN_GBP - IFLA_VXLAN_REMCSUM_NOPARTIAL - IFLA_VXLAN_FLOWBASED - IFLA_VXLAN_MAX = IFLA_VXLAN_FLOWBASED -) - -const ( - BRIDGE_MODE_UNSPEC = iota - BRIDGE_MODE_HAIRPIN -) - -const ( - IFLA_BRPORT_UNSPEC = iota - IFLA_BRPORT_STATE - IFLA_BRPORT_PRIORITY - IFLA_BRPORT_COST - IFLA_BRPORT_MODE - IFLA_BRPORT_GUARD - IFLA_BRPORT_PROTECT - IFLA_BRPORT_FAST_LEAVE - IFLA_BRPORT_LEARNING - IFLA_BRPORT_UNICAST_FLOOD - IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD -) - -const ( - IFLA_IPVLAN_UNSPEC = iota - IFLA_IPVLAN_MODE - IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE -) - -const ( - // not defined in syscall - IFLA_NET_NS_FD = 28 -) - -const ( - IFLA_MACVLAN_UNSPEC = iota - IFLA_MACVLAN_MODE - IFLA_MACVLAN_FLAGS - IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS -) - -const ( - MACVLAN_MODE_PRIVATE = 1 - MACVLAN_MODE_VEPA = 2 - MACVLAN_MODE_BRIDGE = 4 - MACVLAN_MODE_PASSTHRU = 8 - MACVLAN_MODE_SOURCE = 16 -) diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go deleted file mode 100644 index 8dbd92b819e12a1ab5f5e539f3a8be145e7c0870..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ /dev/null @@ -1,418 +0,0 @@ -// Package nl has low level primitives for making Netlink calls. -package nl - -import ( - "bytes" - "encoding/binary" - "fmt" - "net" - "sync/atomic" - "syscall" - "unsafe" -) - -const ( - // Family type definitions - FAMILY_ALL = syscall.AF_UNSPEC - FAMILY_V4 = syscall.AF_INET - FAMILY_V6 = syscall.AF_INET6 -) - -var nextSeqNr uint32 - -// GetIPFamily returns the family type of a net.IP. -func GetIPFamily(ip net.IP) int { - if len(ip) <= net.IPv4len { - return FAMILY_V4 - } - if ip.To4() != nil { - return FAMILY_V4 - } - return FAMILY_V6 -} - -var nativeEndian binary.ByteOrder - -// Get native endianness for the system -func NativeEndian() binary.ByteOrder { - if nativeEndian == nil { - var x uint32 = 0x01020304 - if *(*byte)(unsafe.Pointer(&x)) == 0x01 { - nativeEndian = binary.BigEndian - } else { - nativeEndian = binary.LittleEndian - } - } - return nativeEndian -} - -// Byte swap a 16 bit value if we aren't big endian -func Swap16(i uint16) uint16 { - if NativeEndian() == binary.BigEndian { - return i - } - return (i&0xff00)>>8 | (i&0xff)<<8 -} - -// Byte swap a 32 bit value if aren't big endian -func Swap32(i uint32) uint32 { - if NativeEndian() == binary.BigEndian { - return i - } - return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24 -} - -type NetlinkRequestData interface { - Len() int - Serialize() []byte -} - -// IfInfomsg is related to links, but it is used for list requests as well -type IfInfomsg struct { - syscall.IfInfomsg -} - -// Create an IfInfomsg with family specified -func NewIfInfomsg(family int) *IfInfomsg { - return &IfInfomsg{ - IfInfomsg: syscall.IfInfomsg{ - Family: uint8(family), - }, - } -} - -func DeserializeIfInfomsg(b []byte) *IfInfomsg { - return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0])) -} - -func (msg *IfInfomsg) Serialize() []byte { - return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:] -} - -func (msg *IfInfomsg) Len() int { - return syscall.SizeofIfInfomsg -} - -func rtaAlignOf(attrlen int) int { - return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1) -} - -func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { - msg := NewIfInfomsg(family) - parent.children = append(parent.children, msg) - return msg -} - -// Extend RtAttr to handle data and children -type RtAttr struct { - syscall.RtAttr - Data []byte - children []NetlinkRequestData -} - -// Create a new Extended RtAttr object -func NewRtAttr(attrType int, data []byte) *RtAttr { - return &RtAttr{ - RtAttr: syscall.RtAttr{ - Type: uint16(attrType), - }, - children: []NetlinkRequestData{}, - Data: data, - } -} - -// Create a new RtAttr obj anc add it as a child of an existing object -func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { - attr := NewRtAttr(attrType, data) - parent.children = append(parent.children, attr) - return attr -} - -func (a *RtAttr) Len() int { - if len(a.children) == 0 { - return (syscall.SizeofRtAttr + len(a.Data)) - } - - l := 0 - for _, child := range a.children { - l += rtaAlignOf(child.Len()) - } - l += syscall.SizeofRtAttr - return rtaAlignOf(l + len(a.Data)) -} - -// Serialize the RtAttr into a byte array -// This can't just unsafe.cast because it must iterate through children. -func (a *RtAttr) Serialize() []byte { - native := NativeEndian() - - length := a.Len() - buf := make([]byte, rtaAlignOf(length)) - - if a.Data != nil { - copy(buf[4:], a.Data) - } else { - next := 4 - for _, child := range a.children { - childBuf := child.Serialize() - copy(buf[next:], childBuf) - next += rtaAlignOf(len(childBuf)) - } - } - - if l := uint16(length); l != 0 { - native.PutUint16(buf[0:2], l) - } - native.PutUint16(buf[2:4], a.Type) - return buf -} - -type NetlinkRequest struct { - syscall.NlMsghdr - Data []NetlinkRequestData -} - -// Serialize the Netlink Request into a byte array -func (req *NetlinkRequest) Serialize() []byte { - length := syscall.SizeofNlMsghdr - dataBytes := make([][]byte, len(req.Data)) - for i, data := range req.Data { - dataBytes[i] = data.Serialize() - length = length + len(dataBytes[i]) - } - req.Len = uint32(length) - b := make([]byte, length) - hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:] - next := syscall.SizeofNlMsghdr - copy(b[0:next], hdr) - for _, data := range dataBytes { - for _, dataByte := range data { - b[next] = dataByte - next = next + 1 - } - } - return b -} - -func (req *NetlinkRequest) AddData(data NetlinkRequestData) { - if data != nil { - req.Data = append(req.Data, data) - } -} - -// Execute the request against a the given sockType. -// Returns a list of netlink messages in seriaized format, optionally filtered -// by resType. -func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) { - s, err := getNetlinkSocket(sockType) - if err != nil { - return nil, err - } - defer s.Close() - - if err := s.Send(req); err != nil { - return nil, err - } - - pid, err := s.GetPid() - if err != nil { - return nil, err - } - - var res [][]byte - -done: - for { - msgs, err := s.Receive() - if err != nil { - return nil, err - } - for _, m := range msgs { - if m.Header.Seq != req.Seq { - return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq) - } - if m.Header.Pid != pid { - return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) - } - if m.Header.Type == syscall.NLMSG_DONE { - break done - } - if m.Header.Type == syscall.NLMSG_ERROR { - native := NativeEndian() - error := int32(native.Uint32(m.Data[0:4])) - if error == 0 { - break done - } - return nil, syscall.Errno(-error) - } - if resType != 0 && m.Header.Type != resType { - continue - } - res = append(res, m.Data) - if m.Header.Flags&syscall.NLM_F_MULTI == 0 { - break done - } - } - } - return res, nil -} - -// Create a new netlink request from proto and flags -// Note the Len value will be inaccurate once data is added until -// the message is serialized -func NewNetlinkRequest(proto, flags int) *NetlinkRequest { - return &NetlinkRequest{ - NlMsghdr: syscall.NlMsghdr{ - Len: uint32(syscall.SizeofNlMsghdr), - Type: uint16(proto), - Flags: syscall.NLM_F_REQUEST | uint16(flags), - Seq: atomic.AddUint32(&nextSeqNr, 1), - }, - } -} - -type NetlinkSocket struct { - fd int - lsa syscall.SockaddrNetlink -} - -func getNetlinkSocket(protocol int) (*NetlinkSocket, error) { - fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol) - if err != nil { - return nil, err - } - s := &NetlinkSocket{ - fd: fd, - } - s.lsa.Family = syscall.AF_NETLINK - if err := syscall.Bind(fd, &s.lsa); err != nil { - syscall.Close(fd) - return nil, err - } - - return s, nil -} - -// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE) -// and subscribe it to multicast groups passed in variable argument list. -// Returns the netlink socket on which Receive() method can be called -// to retrieve the messages from the kernel. -func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) { - fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol) - if err != nil { - return nil, err - } - s := &NetlinkSocket{ - fd: fd, - } - s.lsa.Family = syscall.AF_NETLINK - - for _, g := range groups { - s.lsa.Groups |= (1 << (g - 1)) - } - - if err := syscall.Bind(fd, &s.lsa); err != nil { - syscall.Close(fd) - return nil, err - } - - return s, nil -} - -func (s *NetlinkSocket) Close() { - syscall.Close(s.fd) -} - -func (s *NetlinkSocket) Send(request *NetlinkRequest) error { - if err := syscall.Sendto(s.fd, request.Serialize(), 0, &s.lsa); err != nil { - return err - } - return nil -} - -func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) { - rb := make([]byte, syscall.Getpagesize()) - nr, _, err := syscall.Recvfrom(s.fd, rb, 0) - if err != nil { - return nil, err - } - if nr < syscall.NLMSG_HDRLEN { - return nil, fmt.Errorf("Got short response from netlink") - } - rb = rb[:nr] - return syscall.ParseNetlinkMessage(rb) -} - -func (s *NetlinkSocket) GetPid() (uint32, error) { - lsa, err := syscall.Getsockname(s.fd) - if err != nil { - return 0, err - } - switch v := lsa.(type) { - case *syscall.SockaddrNetlink: - return v.Pid, nil - } - return 0, fmt.Errorf("Wrong socket type") -} - -func ZeroTerminated(s string) []byte { - bytes := make([]byte, len(s)+1) - for i := 0; i < len(s); i++ { - bytes[i] = s[i] - } - bytes[len(s)] = 0 - return bytes -} - -func NonZeroTerminated(s string) []byte { - bytes := make([]byte, len(s)) - for i := 0; i < len(s); i++ { - bytes[i] = s[i] - } - return bytes -} - -func BytesToString(b []byte) string { - n := bytes.Index(b, []byte{0}) - return string(b[:n]) -} - -func Uint8Attr(v uint8) []byte { - return []byte{byte(v)} -} - -func Uint16Attr(v uint16) []byte { - native := NativeEndian() - bytes := make([]byte, 2) - native.PutUint16(bytes, v) - return bytes -} - -func Uint32Attr(v uint32) []byte { - native := NativeEndian() - bytes := make([]byte, 4) - native.PutUint32(bytes, v) - return bytes -} - -func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) { - var attrs []syscall.NetlinkRouteAttr - for len(b) >= syscall.SizeofRtAttr { - a, vbuf, alen, err := netlinkRouteAttrAndValue(b) - if err != nil { - return nil, err - } - ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]} - attrs = append(attrs, ra) - b = b[alen:] - } - return attrs, nil -} - -func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) { - a := (*syscall.RtAttr)(unsafe.Pointer(&b[0])) - if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) { - return nil, nil, 0, syscall.EINVAL - } - return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go deleted file mode 100644 index 447e83e5ae5e46649d175642b54a979df8c15cd6..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go +++ /dev/null @@ -1,42 +0,0 @@ -package nl - -import ( - "syscall" - "unsafe" -) - -type RtMsg struct { - syscall.RtMsg -} - -func NewRtMsg() *RtMsg { - return &RtMsg{ - RtMsg: syscall.RtMsg{ - Table: syscall.RT_TABLE_MAIN, - Scope: syscall.RT_SCOPE_UNIVERSE, - Protocol: syscall.RTPROT_BOOT, - Type: syscall.RTN_UNICAST, - }, - } -} - -func NewRtDelMsg() *RtMsg { - return &RtMsg{ - RtMsg: syscall.RtMsg{ - Table: syscall.RT_TABLE_MAIN, - Scope: syscall.RT_SCOPE_NOWHERE, - }, - } -} - -func (msg *RtMsg) Len() int { - return syscall.SizeofRtMsg -} - -func DeserializeRtMsg(b []byte) *RtMsg { - return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0])) -} - -func (msg *RtMsg) Serialize() []byte { - return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go deleted file mode 100644 index c9bfe8dfd8a0d0084459ac927ebb3c2642da8e55..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go +++ /dev/null @@ -1,359 +0,0 @@ -package nl - -import ( - "unsafe" -) - -// Message types -const ( - TCA_UNSPEC = iota - TCA_KIND - TCA_OPTIONS - TCA_STATS - TCA_XSTATS - TCA_RATE - TCA_FCNT - TCA_STATS2 - TCA_STAB - TCA_MAX = TCA_STAB -) - -const ( - TCA_ACT_TAB = 1 - TCAA_MAX = 1 -) - -const ( - TCA_PRIO_UNSPEC = iota - TCA_PRIO_MQ - TCA_PRIO_MAX = TCA_PRIO_MQ -) - -const ( - SizeofTcMsg = 0x14 - SizeofTcActionMsg = 0x04 - SizeofTcPrioMap = 0x14 - SizeofTcRateSpec = 0x0c - SizeofTcTbfQopt = 2*SizeofTcRateSpec + 0x0c - SizeofTcU32Key = 0x10 - SizeofTcU32Sel = 0x10 // without keys - SizeofTcMirred = 0x1c -) - -// struct tcmsg { -// unsigned char tcm_family; -// unsigned char tcm__pad1; -// unsigned short tcm__pad2; -// int tcm_ifindex; -// __u32 tcm_handle; -// __u32 tcm_parent; -// __u32 tcm_info; -// }; - -type TcMsg struct { - Family uint8 - Pad [3]byte - Ifindex int32 - Handle uint32 - Parent uint32 - Info uint32 -} - -func (msg *TcMsg) Len() int { - return SizeofTcMsg -} - -func DeserializeTcMsg(b []byte) *TcMsg { - return (*TcMsg)(unsafe.Pointer(&b[0:SizeofTcMsg][0])) -} - -func (x *TcMsg) Serialize() []byte { - return (*(*[SizeofTcMsg]byte)(unsafe.Pointer(x)))[:] -} - -// struct tcamsg { -// unsigned char tca_family; -// unsigned char tca__pad1; -// unsigned short tca__pad2; -// }; - -type TcActionMsg struct { - Family uint8 - Pad [3]byte -} - -func (msg *TcActionMsg) Len() int { - return SizeofTcActionMsg -} - -func DeserializeTcActionMsg(b []byte) *TcActionMsg { - return (*TcActionMsg)(unsafe.Pointer(&b[0:SizeofTcActionMsg][0])) -} - -func (x *TcActionMsg) Serialize() []byte { - return (*(*[SizeofTcActionMsg]byte)(unsafe.Pointer(x)))[:] -} - -const ( - TC_PRIO_MAX = 15 -) - -// struct tc_prio_qopt { -// int bands; /* Number of bands */ -// __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ -// }; - -type TcPrioMap struct { - Bands int32 - Priomap [TC_PRIO_MAX + 1]uint8 -} - -func (msg *TcPrioMap) Len() int { - return SizeofTcPrioMap -} - -func DeserializeTcPrioMap(b []byte) *TcPrioMap { - return (*TcPrioMap)(unsafe.Pointer(&b[0:SizeofTcPrioMap][0])) -} - -func (x *TcPrioMap) Serialize() []byte { - return (*(*[SizeofTcPrioMap]byte)(unsafe.Pointer(x)))[:] -} - -const ( - TCA_TBF_UNSPEC = iota - TCA_TBF_PARMS - TCA_TBF_RTAB - TCA_TBF_PTAB - TCA_TBF_RATE64 - TCA_TBF_PRATE64 - TCA_TBF_BURST - TCA_TBF_PBURST - TCA_TBF_MAX = TCA_TBF_PBURST -) - -// struct tc_ratespec { -// unsigned char cell_log; -// __u8 linklayer; /* lower 4 bits */ -// unsigned short overhead; -// short cell_align; -// unsigned short mpu; -// __u32 rate; -// }; - -type TcRateSpec struct { - CellLog uint8 - Linklayer uint8 - Overhead uint16 - CellAlign int16 - Mpu uint16 - Rate uint32 -} - -func (msg *TcRateSpec) Len() int { - return SizeofTcRateSpec -} - -func DeserializeTcRateSpec(b []byte) *TcRateSpec { - return (*TcRateSpec)(unsafe.Pointer(&b[0:SizeofTcRateSpec][0])) -} - -func (x *TcRateSpec) Serialize() []byte { - return (*(*[SizeofTcRateSpec]byte)(unsafe.Pointer(x)))[:] -} - -// struct tc_tbf_qopt { -// struct tc_ratespec rate; -// struct tc_ratespec peakrate; -// __u32 limit; -// __u32 buffer; -// __u32 mtu; -// }; - -type TcTbfQopt struct { - Rate TcRateSpec - Peakrate TcRateSpec - Limit uint32 - Buffer uint32 - Mtu uint32 -} - -func (msg *TcTbfQopt) Len() int { - return SizeofTcTbfQopt -} - -func DeserializeTcTbfQopt(b []byte) *TcTbfQopt { - return (*TcTbfQopt)(unsafe.Pointer(&b[0:SizeofTcTbfQopt][0])) -} - -func (x *TcTbfQopt) Serialize() []byte { - return (*(*[SizeofTcTbfQopt]byte)(unsafe.Pointer(x)))[:] -} - -const ( - TCA_U32_UNSPEC = iota - TCA_U32_CLASSID - TCA_U32_HASH - TCA_U32_LINK - TCA_U32_DIVISOR - TCA_U32_SEL - TCA_U32_POLICE - TCA_U32_ACT - TCA_U32_INDEV - TCA_U32_PCNT - TCA_U32_MARK - TCA_U32_MAX = TCA_U32_MARK -) - -// struct tc_u32_key { -// __be32 mask; -// __be32 val; -// int off; -// int offmask; -// }; - -type TcU32Key struct { - Mask uint32 // big endian - Val uint32 // big endian - Off int32 - OffMask int32 -} - -func (msg *TcU32Key) Len() int { - return SizeofTcU32Key -} - -func DeserializeTcU32Key(b []byte) *TcU32Key { - return (*TcU32Key)(unsafe.Pointer(&b[0:SizeofTcU32Key][0])) -} - -func (x *TcU32Key) Serialize() []byte { - return (*(*[SizeofTcU32Key]byte)(unsafe.Pointer(x)))[:] -} - -// struct tc_u32_sel { -// unsigned char flags; -// unsigned char offshift; -// unsigned char nkeys; -// -// __be16 offmask; -// __u16 off; -// short offoff; -// -// short hoff; -// __be32 hmask; -// struct tc_u32_key keys[0]; -// }; - -const ( - TC_U32_TERMINAL = 1 << iota - TC_U32_OFFSET = 1 << iota - TC_U32_VAROFFSET = 1 << iota - TC_U32_EAT = 1 << iota -) - -type TcU32Sel struct { - Flags uint8 - Offshift uint8 - Nkeys uint8 - Pad uint8 - Offmask uint16 // big endian - Off uint16 - Offoff int16 - Hoff int16 - Hmask uint32 // big endian - Keys []TcU32Key -} - -func (msg *TcU32Sel) Len() int { - return SizeofTcU32Sel + int(msg.Nkeys)*SizeofTcU32Key -} - -func DeserializeTcU32Sel(b []byte) *TcU32Sel { - x := &TcU32Sel{} - copy((*(*[SizeofTcU32Sel]byte)(unsafe.Pointer(x)))[:], b) - next := SizeofTcU32Sel - var i uint8 - for i = 0; i < x.Nkeys; i++ { - x.Keys = append(x.Keys, *DeserializeTcU32Key(b[next:])) - next += SizeofTcU32Key - } - return x -} - -func (x *TcU32Sel) Serialize() []byte { - // This can't just unsafe.cast because it must iterate through keys. - buf := make([]byte, x.Len()) - copy(buf, (*(*[SizeofTcU32Sel]byte)(unsafe.Pointer(x)))[:]) - next := SizeofTcU32Sel - for _, key := range x.Keys { - keyBuf := key.Serialize() - copy(buf[next:], keyBuf) - next += SizeofTcU32Key - } - return buf -} - -const ( - TCA_ACT_MIRRED = 8 -) - -const ( - TCA_MIRRED_UNSPEC = iota - TCA_MIRRED_TM - TCA_MIRRED_PARMS - TCA_MIRRED_MAX = TCA_MIRRED_PARMS -) - -const ( - TCA_EGRESS_REDIR = 1 /* packet redirect to EGRESS*/ - TCA_EGRESS_MIRROR = 2 /* mirror packet to EGRESS */ - TCA_INGRESS_REDIR = 3 /* packet redirect to INGRESS*/ - TCA_INGRESS_MIRROR = 4 /* mirror packet to INGRESS */ -) - -const ( - TC_ACT_UNSPEC = int32(-1) - TC_ACT_OK = 0 - TC_ACT_RECLASSIFY = 1 - TC_ACT_SHOT = 2 - TC_ACT_PIPE = 3 - TC_ACT_STOLEN = 4 - TC_ACT_QUEUED = 5 - TC_ACT_REPEAT = 6 - TC_ACT_JUMP = 0x10000000 -) - -// #define tc_gen \ -// __u32 index; \ -// __u32 capab; \ -// int action; \ -// int refcnt; \ -// int bindcnt -// struct tc_mirred { -// tc_gen; -// int eaction; /* one of IN/EGRESS_MIRROR/REDIR */ -// __u32 ifindex; /* ifindex of egress port */ -// }; - -type TcMirred struct { - Index uint32 - Capab uint32 - Action int32 - Refcnt int32 - Bindcnt int32 - Eaction int32 - Ifindex uint32 -} - -func (msg *TcMirred) Len() int { - return SizeofTcMirred -} - -func DeserializeTcMirred(b []byte) *TcMirred { - return (*TcMirred)(unsafe.Pointer(&b[0:SizeofTcMirred][0])) -} - -func (x *TcMirred) Serialize() []byte { - return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go deleted file mode 100644 index d24637d27880f74792d875d91a11b35f13c2ffd9..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go +++ /dev/null @@ -1,258 +0,0 @@ -package nl - -import ( - "bytes" - "net" - "unsafe" -) - -// Infinity for packet and byte counts -const ( - XFRM_INF = ^uint64(0) -) - -// Message Types -const ( - XFRM_MSG_BASE = 0x10 - XFRM_MSG_NEWSA = 0x10 - XFRM_MSG_DELSA = 0x11 - XFRM_MSG_GETSA = 0x12 - XFRM_MSG_NEWPOLICY = 0x13 - XFRM_MSG_DELPOLICY = 0x14 - XFRM_MSG_GETPOLICY = 0x15 - XFRM_MSG_ALLOCSPI = 0x16 - XFRM_MSG_ACQUIRE = 0x17 - XFRM_MSG_EXPIRE = 0x18 - XFRM_MSG_UPDPOLICY = 0x19 - XFRM_MSG_UPDSA = 0x1a - XFRM_MSG_POLEXPIRE = 0x1b - XFRM_MSG_FLUSHSA = 0x1c - XFRM_MSG_FLUSHPOLICY = 0x1d - XFRM_MSG_NEWAE = 0x1e - XFRM_MSG_GETAE = 0x1f - XFRM_MSG_REPORT = 0x20 - XFRM_MSG_MIGRATE = 0x21 - XFRM_MSG_NEWSADINFO = 0x22 - XFRM_MSG_GETSADINFO = 0x23 - XFRM_MSG_NEWSPDINFO = 0x24 - XFRM_MSG_GETSPDINFO = 0x25 - XFRM_MSG_MAPPING = 0x26 - XFRM_MSG_MAX = 0x26 - XFRM_NR_MSGTYPES = 0x17 -) - -// Attribute types -const ( - /* Netlink message attributes. */ - XFRMA_UNSPEC = 0x00 - XFRMA_ALG_AUTH = 0x01 /* struct xfrm_algo */ - XFRMA_ALG_CRYPT = 0x02 /* struct xfrm_algo */ - XFRMA_ALG_COMP = 0x03 /* struct xfrm_algo */ - XFRMA_ENCAP = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */ - XFRMA_TMPL = 0x05 /* 1 or more struct xfrm_user_tmpl */ - XFRMA_SA = 0x06 /* struct xfrm_usersa_info */ - XFRMA_POLICY = 0x07 /* struct xfrm_userpolicy_info */ - XFRMA_SEC_CTX = 0x08 /* struct xfrm_sec_ctx */ - XFRMA_LTIME_VAL = 0x09 - XFRMA_REPLAY_VAL = 0x0a - XFRMA_REPLAY_THRESH = 0x0b - XFRMA_ETIMER_THRESH = 0x0c - XFRMA_SRCADDR = 0x0d /* xfrm_address_t */ - XFRMA_COADDR = 0x0e /* xfrm_address_t */ - XFRMA_LASTUSED = 0x0f /* unsigned long */ - XFRMA_POLICY_TYPE = 0x10 /* struct xfrm_userpolicy_type */ - XFRMA_MIGRATE = 0x11 - XFRMA_ALG_AEAD = 0x12 /* struct xfrm_algo_aead */ - XFRMA_KMADDRESS = 0x13 /* struct xfrm_user_kmaddress */ - XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */ - XFRMA_MARK = 0x15 /* struct xfrm_mark */ - XFRMA_TFCPAD = 0x16 /* __u32 */ - XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */ - XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */ - XFRMA_MAX = 0x18 -) - -const ( - SizeofXfrmAddress = 0x10 - SizeofXfrmSelector = 0x38 - SizeofXfrmLifetimeCfg = 0x40 - SizeofXfrmLifetimeCur = 0x20 - SizeofXfrmId = 0x18 -) - -// typedef union { -// __be32 a4; -// __be32 a6[4]; -// } xfrm_address_t; - -type XfrmAddress [SizeofXfrmAddress]byte - -func (x *XfrmAddress) ToIP() net.IP { - var empty = [12]byte{} - ip := make(net.IP, net.IPv6len) - if bytes.Equal(x[4:16], empty[:]) { - ip[10] = 0xff - ip[11] = 0xff - copy(ip[12:16], x[0:4]) - } else { - copy(ip[:], x[:]) - } - return ip -} - -func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet { - ip := x.ToIP() - if GetIPFamily(ip) == FAMILY_V4 { - return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)} - } - return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)} -} - -func (x *XfrmAddress) FromIP(ip net.IP) { - var empty = [16]byte{} - if len(ip) < net.IPv4len { - copy(x[4:16], empty[:]) - } else if GetIPFamily(ip) == FAMILY_V4 { - copy(x[0:4], ip.To4()[0:4]) - copy(x[4:16], empty[:12]) - } else { - copy(x[0:16], ip.To16()[0:16]) - } -} - -func DeserializeXfrmAddress(b []byte) *XfrmAddress { - return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0])) -} - -func (x *XfrmAddress) Serialize() []byte { - return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(x)))[:] -} - -// struct xfrm_selector { -// xfrm_address_t daddr; -// xfrm_address_t saddr; -// __be16 dport; -// __be16 dport_mask; -// __be16 sport; -// __be16 sport_mask; -// __u16 family; -// __u8 prefixlen_d; -// __u8 prefixlen_s; -// __u8 proto; -// int ifindex; -// __kernel_uid32_t user; -// }; - -type XfrmSelector struct { - Daddr XfrmAddress - Saddr XfrmAddress - Dport uint16 // big endian - DportMask uint16 // big endian - Sport uint16 // big endian - SportMask uint16 // big endian - Family uint16 - PrefixlenD uint8 - PrefixlenS uint8 - Proto uint8 - Pad [3]byte - Ifindex int32 - User uint32 -} - -func (msg *XfrmSelector) Len() int { - return SizeofXfrmSelector -} - -func DeserializeXfrmSelector(b []byte) *XfrmSelector { - return (*XfrmSelector)(unsafe.Pointer(&b[0:SizeofXfrmSelector][0])) -} - -func (msg *XfrmSelector) Serialize() []byte { - return (*(*[SizeofXfrmSelector]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_lifetime_cfg { -// __u64 soft_byte_limit; -// __u64 hard_byte_limit; -// __u64 soft_packet_limit; -// __u64 hard_packet_limit; -// __u64 soft_add_expires_seconds; -// __u64 hard_add_expires_seconds; -// __u64 soft_use_expires_seconds; -// __u64 hard_use_expires_seconds; -// }; -// - -type XfrmLifetimeCfg struct { - SoftByteLimit uint64 - HardByteLimit uint64 - SoftPacketLimit uint64 - HardPacketLimit uint64 - SoftAddExpiresSeconds uint64 - HardAddExpiresSeconds uint64 - SoftUseExpiresSeconds uint64 - HardUseExpiresSeconds uint64 -} - -func (msg *XfrmLifetimeCfg) Len() int { - return SizeofXfrmLifetimeCfg -} - -func DeserializeXfrmLifetimeCfg(b []byte) *XfrmLifetimeCfg { - return (*XfrmLifetimeCfg)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCfg][0])) -} - -func (msg *XfrmLifetimeCfg) Serialize() []byte { - return (*(*[SizeofXfrmLifetimeCfg]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_lifetime_cur { -// __u64 bytes; -// __u64 packets; -// __u64 add_time; -// __u64 use_time; -// }; - -type XfrmLifetimeCur struct { - Bytes uint64 - Packets uint64 - AddTime uint64 - UseTime uint64 -} - -func (msg *XfrmLifetimeCur) Len() int { - return SizeofXfrmLifetimeCur -} - -func DeserializeXfrmLifetimeCur(b []byte) *XfrmLifetimeCur { - return (*XfrmLifetimeCur)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCur][0])) -} - -func (msg *XfrmLifetimeCur) Serialize() []byte { - return (*(*[SizeofXfrmLifetimeCur]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_id { -// xfrm_address_t daddr; -// __be32 spi; -// __u8 proto; -// }; - -type XfrmId struct { - Daddr XfrmAddress - Spi uint32 // big endian - Proto uint8 - Pad [3]byte -} - -func (msg *XfrmId) Len() int { - return SizeofXfrmId -} - -func DeserializeXfrmId(b []byte) *XfrmId { - return (*XfrmId)(unsafe.Pointer(&b[0:SizeofXfrmId][0])) -} - -func (msg *XfrmId) Serialize() []byte { - return (*(*[SizeofXfrmId]byte)(unsafe.Pointer(msg)))[:] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go deleted file mode 100644 index 66f7e03d2d7f2a73a796eb8013adc018e6aa039f..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go +++ /dev/null @@ -1,119 +0,0 @@ -package nl - -import ( - "unsafe" -) - -const ( - SizeofXfrmUserpolicyId = 0x40 - SizeofXfrmUserpolicyInfo = 0xa8 - SizeofXfrmUserTmpl = 0x40 -) - -// struct xfrm_userpolicy_id { -// struct xfrm_selector sel; -// __u32 index; -// __u8 dir; -// }; -// - -type XfrmUserpolicyId struct { - Sel XfrmSelector - Index uint32 - Dir uint8 - Pad [3]byte -} - -func (msg *XfrmUserpolicyId) Len() int { - return SizeofXfrmUserpolicyId -} - -func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId { - return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0])) -} - -func (msg *XfrmUserpolicyId) Serialize() []byte { - return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_userpolicy_info { -// struct xfrm_selector sel; -// struct xfrm_lifetime_cfg lft; -// struct xfrm_lifetime_cur curlft; -// __u32 priority; -// __u32 index; -// __u8 dir; -// __u8 action; -// #define XFRM_POLICY_ALLOW 0 -// #define XFRM_POLICY_BLOCK 1 -// __u8 flags; -// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */ -// /* Automatically expand selector to include matching ICMP payloads. */ -// #define XFRM_POLICY_ICMP 2 -// __u8 share; -// }; - -type XfrmUserpolicyInfo struct { - Sel XfrmSelector - Lft XfrmLifetimeCfg - Curlft XfrmLifetimeCur - Priority uint32 - Index uint32 - Dir uint8 - Action uint8 - Flags uint8 - Share uint8 - Pad [4]byte -} - -func (msg *XfrmUserpolicyInfo) Len() int { - return SizeofXfrmUserpolicyInfo -} - -func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo { - return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0])) -} - -func (msg *XfrmUserpolicyInfo) Serialize() []byte { - return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_user_tmpl { -// struct xfrm_id id; -// __u16 family; -// xfrm_address_t saddr; -// __u32 reqid; -// __u8 mode; -// __u8 share; -// __u8 optional; -// __u32 aalgos; -// __u32 ealgos; -// __u32 calgos; -// } - -type XfrmUserTmpl struct { - XfrmId XfrmId - Family uint16 - Pad1 [2]byte - Saddr XfrmAddress - Reqid uint32 - Mode uint8 - Share uint8 - Optional uint8 - Pad2 byte - Aalgos uint32 - Ealgos uint32 - Calgos uint32 -} - -func (msg *XfrmUserTmpl) Len() int { - return SizeofXfrmUserTmpl -} - -func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl { - return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0])) -} - -func (msg *XfrmUserTmpl) Serialize() []byte { - return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go deleted file mode 100644 index 4876ce458371f5828807198dc92476e77ec47b55..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go +++ /dev/null @@ -1,221 +0,0 @@ -package nl - -import ( - "unsafe" -) - -const ( - SizeofXfrmUsersaId = 0x18 - SizeofXfrmStats = 0x0c - SizeofXfrmUsersaInfo = 0xe0 - SizeofXfrmAlgo = 0x44 - SizeofXfrmAlgoAuth = 0x48 - SizeofXfrmEncapTmpl = 0x18 -) - -// struct xfrm_usersa_id { -// xfrm_address_t daddr; -// __be32 spi; -// __u16 family; -// __u8 proto; -// }; - -type XfrmUsersaId struct { - Daddr XfrmAddress - Spi uint32 // big endian - Family uint16 - Proto uint8 - Pad byte -} - -func (msg *XfrmUsersaId) Len() int { - return SizeofXfrmUsersaId -} - -func DeserializeXfrmUsersaId(b []byte) *XfrmUsersaId { - return (*XfrmUsersaId)(unsafe.Pointer(&b[0:SizeofXfrmUsersaId][0])) -} - -func (msg *XfrmUsersaId) Serialize() []byte { - return (*(*[SizeofXfrmUsersaId]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_stats { -// __u32 replay_window; -// __u32 replay; -// __u32 integrity_failed; -// }; - -type XfrmStats struct { - ReplayWindow uint32 - Replay uint32 - IntegrityFailed uint32 -} - -func (msg *XfrmStats) Len() int { - return SizeofXfrmStats -} - -func DeserializeXfrmStats(b []byte) *XfrmStats { - return (*XfrmStats)(unsafe.Pointer(&b[0:SizeofXfrmStats][0])) -} - -func (msg *XfrmStats) Serialize() []byte { - return (*(*[SizeofXfrmStats]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_usersa_info { -// struct xfrm_selector sel; -// struct xfrm_id id; -// xfrm_address_t saddr; -// struct xfrm_lifetime_cfg lft; -// struct xfrm_lifetime_cur curlft; -// struct xfrm_stats stats; -// __u32 seq; -// __u32 reqid; -// __u16 family; -// __u8 mode; /* XFRM_MODE_xxx */ -// __u8 replay_window; -// __u8 flags; -// #define XFRM_STATE_NOECN 1 -// #define XFRM_STATE_DECAP_DSCP 2 -// #define XFRM_STATE_NOPMTUDISC 4 -// #define XFRM_STATE_WILDRECV 8 -// #define XFRM_STATE_ICMP 16 -// #define XFRM_STATE_AF_UNSPEC 32 -// #define XFRM_STATE_ALIGN4 64 -// #define XFRM_STATE_ESN 128 -// }; -// -// #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1 -// - -type XfrmUsersaInfo struct { - Sel XfrmSelector - Id XfrmId - Saddr XfrmAddress - Lft XfrmLifetimeCfg - Curlft XfrmLifetimeCur - Stats XfrmStats - Seq uint32 - Reqid uint32 - Family uint16 - Mode uint8 - ReplayWindow uint8 - Flags uint8 - Pad [7]byte -} - -func (msg *XfrmUsersaInfo) Len() int { - return SizeofXfrmUsersaInfo -} - -func DeserializeXfrmUsersaInfo(b []byte) *XfrmUsersaInfo { - return (*XfrmUsersaInfo)(unsafe.Pointer(&b[0:SizeofXfrmUsersaInfo][0])) -} - -func (msg *XfrmUsersaInfo) Serialize() []byte { - return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_algo { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// char alg_key[0]; -// }; - -type XfrmAlgo struct { - AlgName [64]byte - AlgKeyLen uint32 - AlgKey []byte -} - -func (msg *XfrmAlgo) Len() int { - return SizeofXfrmAlgo + int(msg.AlgKeyLen/8) -} - -func DeserializeXfrmAlgo(b []byte) *XfrmAlgo { - ret := XfrmAlgo{} - copy(ret.AlgName[:], b[0:64]) - ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) - ret.AlgKey = b[68:ret.Len()] - return &ret -} - -func (msg *XfrmAlgo) Serialize() []byte { - b := make([]byte, msg.Len()) - copy(b[0:64], msg.AlgName[:]) - copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) - copy(b[68:msg.Len()], msg.AlgKey[:]) - return b -} - -// struct xfrm_algo_auth { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// unsigned int alg_trunc_len; /* in bits */ -// char alg_key[0]; -// }; - -type XfrmAlgoAuth struct { - AlgName [64]byte - AlgKeyLen uint32 - AlgTruncLen uint32 - AlgKey []byte -} - -func (msg *XfrmAlgoAuth) Len() int { - return SizeofXfrmAlgoAuth + int(msg.AlgKeyLen/8) -} - -func DeserializeXfrmAlgoAuth(b []byte) *XfrmAlgoAuth { - ret := XfrmAlgoAuth{} - copy(ret.AlgName[:], b[0:64]) - ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) - ret.AlgTruncLen = *(*uint32)(unsafe.Pointer(&b[68])) - ret.AlgKey = b[72:ret.Len()] - return &ret -} - -func (msg *XfrmAlgoAuth) Serialize() []byte { - b := make([]byte, msg.Len()) - copy(b[0:64], msg.AlgName[:]) - copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) - copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgTruncLen)))[:]) - copy(b[72:msg.Len()], msg.AlgKey[:]) - return b -} - -// struct xfrm_algo_aead { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// unsigned int alg_icv_len; /* in bits */ -// char alg_key[0]; -// } - -// struct xfrm_encap_tmpl { -// __u16 encap_type; -// __be16 encap_sport; -// __be16 encap_dport; -// xfrm_address_t encap_oa; -// }; - -type XfrmEncapTmpl struct { - EncapType uint16 - EncapSport uint16 // big endian - EncapDport uint16 // big endian - Pad [2]byte - EncapOa XfrmAddress -} - -func (msg *XfrmEncapTmpl) Len() int { - return SizeofXfrmEncapTmpl -} - -func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl { - return (*XfrmEncapTmpl)(unsafe.Pointer(&b[0:SizeofXfrmEncapTmpl][0])) -} - -func (msg *XfrmEncapTmpl) Serialize() []byte { - return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:] -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go deleted file mode 100644 index f39ab8f4e8886d0ee99dff287d184437a7f3546a..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go +++ /dev/null @@ -1,53 +0,0 @@ -package netlink - -import ( - "strings" -) - -// Protinfo represents bridge flags from netlink. -type Protinfo struct { - Hairpin bool - Guard bool - FastLeave bool - RootBlock bool - Learning bool - Flood bool -} - -// String returns a list of enabled flags -func (prot *Protinfo) String() string { - var boolStrings []string - if prot.Hairpin { - boolStrings = append(boolStrings, "Hairpin") - } - if prot.Guard { - boolStrings = append(boolStrings, "Guard") - } - if prot.FastLeave { - boolStrings = append(boolStrings, "FastLeave") - } - if prot.RootBlock { - boolStrings = append(boolStrings, "RootBlock") - } - if prot.Learning { - boolStrings = append(boolStrings, "Learning") - } - if prot.Flood { - boolStrings = append(boolStrings, "Flood") - } - return strings.Join(boolStrings, " ") -} - -func boolToByte(x bool) []byte { - if x { - return []byte{1} - } - return []byte{0} -} - -func byteToBool(x byte) bool { - if uint8(x) != 0 { - return true - } - return false -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go deleted file mode 100644 index 7181eba100dd6e04b67afa70c0c0cd06108caf91..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go +++ /dev/null @@ -1,60 +0,0 @@ -package netlink - -import ( - "fmt" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -func LinkGetProtinfo(link Link) (Protinfo, error) { - base := link.Attrs() - ensureIndex(base) - var pi Protinfo - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) - msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) - req.AddData(msg) - msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0) - if err != nil { - return pi, err - } - - for _, m := range msgs { - ans := nl.DeserializeIfInfomsg(m) - if int(ans.Index) != base.Index { - continue - } - attrs, err := nl.ParseRouteAttr(m[ans.Len():]) - if err != nil { - return pi, err - } - for _, attr := range attrs { - if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED { - continue - } - infos, err := nl.ParseRouteAttr(attr.Value) - if err != nil { - return pi, err - } - var pi Protinfo - for _, info := range infos { - switch info.Attr.Type { - case nl.IFLA_BRPORT_MODE: - pi.Hairpin = byteToBool(info.Value[0]) - case nl.IFLA_BRPORT_GUARD: - pi.Guard = byteToBool(info.Value[0]) - case nl.IFLA_BRPORT_FAST_LEAVE: - pi.FastLeave = byteToBool(info.Value[0]) - case nl.IFLA_BRPORT_PROTECT: - pi.RootBlock = byteToBool(info.Value[0]) - case nl.IFLA_BRPORT_LEARNING: - pi.Learning = byteToBool(info.Value[0]) - case nl.IFLA_BRPORT_UNICAST_FLOOD: - pi.Flood = byteToBool(info.Value[0]) - } - } - return pi, nil - } - } - return pi, fmt.Errorf("Device with index %d not found", base.Index) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go deleted file mode 100644 index 8e3d020fd4c0de8847700fd989dfebc4068db4b7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go +++ /dev/null @@ -1,138 +0,0 @@ -package netlink - -import ( - "fmt" -) - -const ( - HANDLE_NONE = 0 - HANDLE_INGRESS = 0xFFFFFFF1 - HANDLE_ROOT = 0xFFFFFFFF - PRIORITY_MAP_LEN = 16 -) - -type Qdisc interface { - Attrs() *QdiscAttrs - Type() string -} - -// Qdisc represents a netlink qdisc. A qdisc is associated with a link, -// has a handle, a parent and a refcnt. The root qdisc of a device should -// have parent == HANDLE_ROOT. -type QdiscAttrs struct { - LinkIndex int - Handle uint32 - Parent uint32 - Refcnt uint32 // read only -} - -func (q QdiscAttrs) String() string { - return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt) -} - -func MakeHandle(major, minor uint16) uint32 { - return (uint32(major) << 16) | uint32(minor) -} - -func MajorMinor(handle uint32) (uint16, uint16) { - return uint16((handle & 0xFFFF0000) >> 16), uint16(handle & 0x0000FFFFF) -} - -func HandleStr(handle uint32) string { - switch handle { - case HANDLE_NONE: - return "none" - case HANDLE_INGRESS: - return "ingress" - case HANDLE_ROOT: - return "root" - default: - major, minor := MajorMinor(handle) - return fmt.Sprintf("%x:%x", major, minor) - } -} - -// PfifoFast is the default qdisc created by the kernel if one has not -// been defined for the interface -type PfifoFast struct { - QdiscAttrs - Bands uint8 - PriorityMap [PRIORITY_MAP_LEN]uint8 -} - -func (qdisc *PfifoFast) Attrs() *QdiscAttrs { - return &qdisc.QdiscAttrs -} - -func (qdisc *PfifoFast) Type() string { - return "pfifo_fast" -} - -// Prio is a basic qdisc that works just like PfifoFast -type Prio struct { - QdiscAttrs - Bands uint8 - PriorityMap [PRIORITY_MAP_LEN]uint8 -} - -func NewPrio(attrs QdiscAttrs) *Prio { - return &Prio{ - QdiscAttrs: attrs, - Bands: 3, - PriorityMap: [PRIORITY_MAP_LEN]uint8{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, - } -} - -func (qdisc *Prio) Attrs() *QdiscAttrs { - return &qdisc.QdiscAttrs -} - -func (qdisc *Prio) Type() string { - return "prio" -} - -// Tbf is a classful qdisc that rate limits based on tokens -type Tbf struct { - QdiscAttrs - // TODO: handle 64bit rate properly - Rate uint64 - Limit uint32 - Buffer uint32 - // TODO: handle other settings -} - -func (qdisc *Tbf) Attrs() *QdiscAttrs { - return &qdisc.QdiscAttrs -} - -func (qdisc *Tbf) Type() string { - return "tbf" -} - -// Ingress is a qdisc for adding ingress filters -type Ingress struct { - QdiscAttrs -} - -func (qdisc *Ingress) Attrs() *QdiscAttrs { - return &qdisc.QdiscAttrs -} - -func (qdisc *Ingress) Type() string { - return "ingress" -} - -// GenericQdisc qdiscs represent types that are not currently understood -// by this netlink library. -type GenericQdisc struct { - QdiscAttrs - QdiscType string -} - -func (qdisc *GenericQdisc) Attrs() *QdiscAttrs { - return &qdisc.QdiscAttrs -} - -func (qdisc *GenericQdisc) Type() string { - return qdisc.QdiscType -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go deleted file mode 100644 index 2531c9dd13c4b4f223a044cba07150ef2a815a36..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go +++ /dev/null @@ -1,263 +0,0 @@ -package netlink - -import ( - "fmt" - "io/ioutil" - "strconv" - "strings" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -// QdiscDel will delete a qdisc from the system. -// Equivalent to: `tc qdisc del $qdisc` -func QdiscDel(qdisc Qdisc) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELQDISC, syscall.NLM_F_ACK) - base := qdisc.Attrs() - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Ifindex: int32(base.LinkIndex), - Handle: base.Handle, - Parent: base.Parent, - } - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// QdiscAdd will add a qdisc to the system. -// Equivalent to: `tc qdisc add $qdisc` -func QdiscAdd(qdisc Qdisc) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWQDISC, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - base := qdisc.Attrs() - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Ifindex: int32(base.LinkIndex), - Handle: base.Handle, - Parent: base.Parent, - } - req.AddData(msg) - req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(qdisc.Type()))) - - options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) - if prio, ok := qdisc.(*Prio); ok { - tcmap := nl.TcPrioMap{ - Bands: int32(prio.Bands), - Priomap: prio.PriorityMap, - } - options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize()) - } else if tbf, ok := qdisc.(*Tbf); ok { - opt := nl.TcTbfQopt{} - // TODO: handle rate > uint32 - opt.Rate.Rate = uint32(tbf.Rate) - opt.Limit = tbf.Limit - opt.Buffer = tbf.Buffer - nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize()) - } else if _, ok := qdisc.(*Ingress); ok { - // ingress filters must use the proper handle - if msg.Parent != HANDLE_INGRESS { - return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS") - } - } - req.AddData(options) - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// QdiscList gets a list of qdiscs in the system. -// Equivalent to: `tc qdisc show`. -// The list can be filtered by link. -func QdiscList(link Link) ([]Qdisc, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP) - index := int32(0) - if link != nil { - base := link.Attrs() - ensureIndex(base) - index = int32(base.Index) - } - msg := &nl.TcMsg{ - Family: nl.FAMILY_ALL, - Ifindex: index, - } - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWQDISC) - if err != nil { - return nil, err - } - - var res []Qdisc - for _, m := range msgs { - msg := nl.DeserializeTcMsg(m) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - // skip qdiscs from other interfaces - if link != nil && msg.Ifindex != index { - continue - } - - base := QdiscAttrs{ - LinkIndex: int(msg.Ifindex), - Handle: msg.Handle, - Parent: msg.Parent, - Refcnt: msg.Info, - } - var qdisc Qdisc - qdiscType := "" - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.TCA_KIND: - qdiscType = string(attr.Value[:len(attr.Value)-1]) - switch qdiscType { - case "pfifo_fast": - qdisc = &PfifoFast{} - case "prio": - qdisc = &Prio{} - case "tbf": - qdisc = &Tbf{} - case "ingress": - qdisc = &Ingress{} - default: - qdisc = &GenericQdisc{QdiscType: qdiscType} - } - case nl.TCA_OPTIONS: - switch qdiscType { - case "pfifo_fast": - // pfifo returns TcPrioMap directly without wrapping it in rtattr - if err := parsePfifoFastData(qdisc, attr.Value); err != nil { - return nil, err - } - case "prio": - // prio returns TcPrioMap directly without wrapping it in rtattr - if err := parsePrioData(qdisc, attr.Value); err != nil { - return nil, err - } - case "tbf": - data, err := nl.ParseRouteAttr(attr.Value) - if err != nil { - return nil, err - } - if err := parseTbfData(qdisc, data); err != nil { - return nil, err - } - // no options for ingress - } - } - } - *qdisc.Attrs() = base - res = append(res, qdisc) - } - - return res, nil -} - -func parsePfifoFastData(qdisc Qdisc, value []byte) error { - pfifo := qdisc.(*PfifoFast) - tcmap := nl.DeserializeTcPrioMap(value) - pfifo.PriorityMap = tcmap.Priomap - pfifo.Bands = uint8(tcmap.Bands) - return nil -} - -func parsePrioData(qdisc Qdisc, value []byte) error { - prio := qdisc.(*Prio) - tcmap := nl.DeserializeTcPrioMap(value) - prio.PriorityMap = tcmap.Priomap - prio.Bands = uint8(tcmap.Bands) - return nil -} - -func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { - native = nl.NativeEndian() - tbf := qdisc.(*Tbf) - for _, datum := range data { - switch datum.Attr.Type { - case nl.TCA_TBF_PARMS: - opt := nl.DeserializeTcTbfQopt(datum.Value) - tbf.Rate = uint64(opt.Rate.Rate) - tbf.Limit = opt.Limit - tbf.Buffer = opt.Buffer - case nl.TCA_TBF_RATE64: - tbf.Rate = native.Uint64(datum.Value[0:4]) - } - } - return nil -} - -const ( - TIME_UNITS_PER_SEC = 1000000 -) - -var ( - tickInUsec float64 = 0.0 - clockFactor float64 = 0.0 -) - -func initClock() { - data, err := ioutil.ReadFile("/proc/net/psched") - if err != nil { - return - } - parts := strings.Split(strings.TrimSpace(string(data)), " ") - if len(parts) < 3 { - return - } - var vals [3]uint64 - for i := range vals { - val, err := strconv.ParseUint(parts[i], 16, 32) - if err != nil { - return - } - vals[i] = val - } - // compatibility - if vals[2] == 1000000000 { - vals[0] = vals[1] - } - clockFactor = float64(vals[2]) / TIME_UNITS_PER_SEC - tickInUsec = float64(vals[0]) / float64(vals[1]) * clockFactor -} - -func TickInUsec() float64 { - if tickInUsec == 0.0 { - initClock() - } - return tickInUsec -} - -func ClockFactor() float64 { - if clockFactor == 0.0 { - initClock() - } - return clockFactor -} - -func time2Tick(time uint32) uint32 { - return uint32(float64(time) * TickInUsec()) -} - -func tick2Time(tick uint32) uint32 { - return uint32(float64(tick) / TickInUsec()) -} - -func time2Ktime(time uint32) uint32 { - return uint32(float64(time) * ClockFactor()) -} - -func ktime2Time(ktime uint32) uint32 { - return uint32(float64(ktime) / ClockFactor()) -} - -func burst(rate uint64, buffer uint32) uint32 { - return uint32(float64(rate) * float64(tick2Time(buffer)) / TIME_UNITS_PER_SEC) -} - -func latency(rate uint64, limit, buffer uint32) float64 { - return TIME_UNITS_PER_SEC*(float64(limit)/float64(rate)) - float64(tick2Time(buffer)) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go deleted file mode 100644 index 6218546f8028b63fb73a49de48af0d87ae353983..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go +++ /dev/null @@ -1,35 +0,0 @@ -package netlink - -import ( - "fmt" - "net" - "syscall" -) - -// Scope is an enum representing a route scope. -type Scope uint8 - -const ( - SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE - SCOPE_SITE Scope = syscall.RT_SCOPE_SITE - SCOPE_LINK Scope = syscall.RT_SCOPE_LINK - SCOPE_HOST Scope = syscall.RT_SCOPE_HOST - SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE -) - -// Route represents a netlink route. A route is associated with a link, -// has a destination network, an optional source ip, and optional -// gateway. Advanced route parameters and non-main routing tables are -// currently not supported. -type Route struct { - LinkIndex int - Scope Scope - Dst *net.IPNet - Src net.IP - Gw net.IP -} - -func (r Route) String() string { - return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst, - r.Src, r.Gw) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go deleted file mode 100644 index 9e76d4414488e689ee75f74d1a804a0dbf7f6955..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go +++ /dev/null @@ -1,225 +0,0 @@ -package netlink - -import ( - "fmt" - "net" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -// RtAttr is shared so it is in netlink_linux.go - -// RouteAdd will add a route to the system. -// Equivalent to: `ip route add $route` -func RouteAdd(route *Route) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - return routeHandle(route, req, nl.NewRtMsg()) -} - -// RouteAdd will delete a route from the system. -// Equivalent to: `ip route del $route` -func RouteDel(route *Route) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) - return routeHandle(route, req, nl.NewRtDelMsg()) -} - -func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { - if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil { - return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil") - } - - msg.Scope = uint8(route.Scope) - family := -1 - var rtAttrs []*nl.RtAttr - - if route.Dst != nil && route.Dst.IP != nil { - dstLen, _ := route.Dst.Mask.Size() - msg.Dst_len = uint8(dstLen) - dstFamily := nl.GetIPFamily(route.Dst.IP) - family = dstFamily - var dstData []byte - if dstFamily == FAMILY_V4 { - dstData = route.Dst.IP.To4() - } else { - dstData = route.Dst.IP.To16() - } - rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData)) - } - - if route.Src != nil { - srcFamily := nl.GetIPFamily(route.Src) - if family != -1 && family != srcFamily { - return fmt.Errorf("source and destination ip are not the same IP family") - } - family = srcFamily - var srcData []byte - if srcFamily == FAMILY_V4 { - srcData = route.Src.To4() - } else { - srcData = route.Src.To16() - } - // The commonly used src ip for routes is actually PREFSRC - rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData)) - } - - if route.Gw != nil { - gwFamily := nl.GetIPFamily(route.Gw) - if family != -1 && family != gwFamily { - return fmt.Errorf("gateway, source, and destination ip are not the same IP family") - } - family = gwFamily - var gwData []byte - if gwFamily == FAMILY_V4 { - gwData = route.Gw.To4() - } else { - gwData = route.Gw.To16() - } - rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData)) - } - - msg.Family = uint8(family) - - req.AddData(msg) - for _, attr := range rtAttrs { - req.AddData(attr) - } - - var ( - b = make([]byte, 4) - native = nl.NativeEndian() - ) - native.PutUint32(b, uint32(route.LinkIndex)) - - req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b)) - - _, err := req.Execute(syscall.NETLINK_ROUTE, 0) - return err -} - -// RouteList gets a list of routes in the system. -// Equivalent to: `ip route show`. -// The list can be filtered by link and ip family. -func RouteList(link Link, family int) ([]Route, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) - msg := nl.NewIfInfomsg(family) - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) - if err != nil { - return nil, err - } - - index := 0 - if link != nil { - base := link.Attrs() - ensureIndex(base) - index = base.Index - } - - native := nl.NativeEndian() - var res []Route -MsgLoop: - for _, m := range msgs { - msg := nl.DeserializeRtMsg(m) - - if msg.Flags&syscall.RTM_F_CLONED != 0 { - // Ignore cloned routes - continue - } - - if msg.Table != syscall.RT_TABLE_MAIN { - // Ignore non-main tables - continue - } - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - route := Route{Scope: Scope(msg.Scope)} - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.RTA_GATEWAY: - route.Gw = net.IP(attr.Value) - case syscall.RTA_PREFSRC: - route.Src = net.IP(attr.Value) - case syscall.RTA_DST: - route.Dst = &net.IPNet{ - IP: attr.Value, - Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), - } - case syscall.RTA_OIF: - routeIndex := int(native.Uint32(attr.Value[0:4])) - if link != nil && routeIndex != index { - // Ignore routes from other interfaces - continue MsgLoop - } - route.LinkIndex = routeIndex - } - } - res = append(res, route) - } - - return res, nil -} - -// RouteGet gets a route to a specific destination from the host system. -// Equivalent to: 'ip route get'. -func RouteGet(destination net.IP) ([]Route, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST) - family := nl.GetIPFamily(destination) - var destinationData []byte - var bitlen uint8 - if family == FAMILY_V4 { - destinationData = destination.To4() - bitlen = 32 - } else { - destinationData = destination.To16() - bitlen = 128 - } - msg := &nl.RtMsg{} - msg.Family = uint8(family) - msg.Dst_len = bitlen - req.AddData(msg) - - rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData) - req.AddData(rtaDst) - - msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) - if err != nil { - return nil, err - } - - native := nl.NativeEndian() - var res []Route - for _, m := range msgs { - msg := nl.DeserializeRtMsg(m) - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - route := Route{} - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.RTA_GATEWAY: - route.Gw = net.IP(attr.Value) - case syscall.RTA_PREFSRC: - route.Src = net.IP(attr.Value) - case syscall.RTA_DST: - route.Dst = &net.IPNet{ - IP: attr.Value, - Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), - } - case syscall.RTA_OIF: - routeIndex := int(native.Uint32(attr.Value[0:4])) - route.LinkIndex = routeIndex - } - } - res = append(res, route) - } - return res, nil - -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go deleted file mode 100644 index 621ffb6c6847ec42384cc59a0c0244037bc03af0..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go +++ /dev/null @@ -1,64 +0,0 @@ -package netlink - -import ( - "fmt" - "syscall" -) - -// Proto is an enum representing an ipsec protocol. -type Proto uint8 - -const ( - XFRM_PROTO_ROUTE2 Proto = syscall.IPPROTO_ROUTING - XFRM_PROTO_ESP Proto = syscall.IPPROTO_ESP - XFRM_PROTO_AH Proto = syscall.IPPROTO_AH - XFRM_PROTO_HAO Proto = syscall.IPPROTO_DSTOPTS - XFRM_PROTO_COMP Proto = syscall.IPPROTO_COMP - XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW -) - -func (p Proto) String() string { - switch p { - case XFRM_PROTO_ROUTE2: - return "route2" - case XFRM_PROTO_ESP: - return "esp" - case XFRM_PROTO_AH: - return "ah" - case XFRM_PROTO_HAO: - return "hao" - case XFRM_PROTO_COMP: - return "comp" - case XFRM_PROTO_IPSEC_ANY: - return "ipsec-any" - } - return fmt.Sprintf("%d", p) -} - -// Mode is an enum representing an ipsec transport. -type Mode uint8 - -const ( - XFRM_MODE_TRANSPORT Mode = iota - XFRM_MODE_TUNNEL - XFRM_MODE_ROUTEOPTIMIZATION - XFRM_MODE_IN_TRIGGER - XFRM_MODE_BEET - XFRM_MODE_MAX -) - -func (m Mode) String() string { - switch m { - case XFRM_MODE_TRANSPORT: - return "transport" - case XFRM_MODE_TUNNEL: - return "tunnel" - case XFRM_MODE_ROUTEOPTIMIZATION: - return "ro" - case XFRM_MODE_IN_TRIGGER: - return "in_trigger" - case XFRM_MODE_BEET: - return "beet" - } - return fmt.Sprintf("%d", m) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go deleted file mode 100644 index d85c65d2d2a75ab97aeb937c295ef66db66c0fac..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go +++ /dev/null @@ -1,59 +0,0 @@ -package netlink - -import ( - "fmt" - "net" -) - -// Dir is an enum representing an ipsec template direction. -type Dir uint8 - -const ( - XFRM_DIR_IN Dir = iota - XFRM_DIR_OUT - XFRM_DIR_FWD - XFRM_SOCKET_IN - XFRM_SOCKET_OUT - XFRM_SOCKET_FWD -) - -func (d Dir) String() string { - switch d { - case XFRM_DIR_IN: - return "dir in" - case XFRM_DIR_OUT: - return "dir out" - case XFRM_DIR_FWD: - return "dir fwd" - case XFRM_SOCKET_IN: - return "socket in" - case XFRM_SOCKET_OUT: - return "socket out" - case XFRM_SOCKET_FWD: - return "socket fwd" - } - return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN) -} - -// XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec -// policy. These rules are matched with XfrmState to determine encryption -// and authentication algorithms. -type XfrmPolicyTmpl struct { - Dst net.IP - Src net.IP - Proto Proto - Mode Mode - Reqid int -} - -// XfrmPolicy represents an ipsec policy. It represents the overlay network -// and has a list of XfrmPolicyTmpls representing the base addresses of -// the policy. -type XfrmPolicy struct { - Dst *net.IPNet - Src *net.IPNet - Dir Dir - Priority int - Index int - Tmpls []XfrmPolicyTmpl -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go deleted file mode 100644 index 2daf6dc8b3374ba22c795071209e3cf5b0750c55..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go +++ /dev/null @@ -1,127 +0,0 @@ -package netlink - -import ( - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { - sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP)) - sel.Daddr.FromIP(policy.Dst.IP) - sel.Saddr.FromIP(policy.Src.IP) - prefixlenD, _ := policy.Dst.Mask.Size() - sel.PrefixlenD = uint8(prefixlenD) - prefixlenS, _ := policy.Src.Mask.Size() - sel.PrefixlenS = uint8(prefixlenS) -} - -// XfrmPolicyAdd will add an xfrm policy to the system. -// Equivalent to: `ip xfrm policy add $policy` -func XfrmPolicyAdd(policy *XfrmPolicy) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := &nl.XfrmUserpolicyInfo{} - selFromPolicy(&msg.Sel, policy) - msg.Priority = uint32(policy.Priority) - msg.Index = uint32(policy.Index) - msg.Dir = uint8(policy.Dir) - msg.Lft.SoftByteLimit = nl.XFRM_INF - msg.Lft.HardByteLimit = nl.XFRM_INF - msg.Lft.SoftPacketLimit = nl.XFRM_INF - msg.Lft.HardPacketLimit = nl.XFRM_INF - req.AddData(msg) - - tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls)) - for i, tmpl := range policy.Tmpls { - start := i * nl.SizeofXfrmUserTmpl - userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl]) - userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst) - userTmpl.Saddr.FromIP(tmpl.Src) - userTmpl.XfrmId.Proto = uint8(tmpl.Proto) - userTmpl.Mode = uint8(tmpl.Mode) - userTmpl.Reqid = uint32(tmpl.Reqid) - userTmpl.Aalgos = ^uint32(0) - userTmpl.Ealgos = ^uint32(0) - userTmpl.Calgos = ^uint32(0) - } - if len(tmplData) > 0 { - tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) - req.AddData(tmpls) - } - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) - return err -} - -// XfrmPolicyDel will delete an xfrm policy from the system. Note that -// the Tmpls are ignored when matching the policy to delete. -// Equivalent to: `ip xfrm policy del $policy` -func XfrmPolicyDel(policy *XfrmPolicy) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK) - - msg := &nl.XfrmUserpolicyId{} - selFromPolicy(&msg.Sel, policy) - msg.Index = uint32(policy.Index) - msg.Dir = uint8(policy.Dir) - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) - return err -} - -// XfrmPolicyList gets a list of xfrm policies in the system. -// Equivalent to: `ip xfrm policy show`. -// The list can be filtered by ip family. -func XfrmPolicyList(family int) ([]XfrmPolicy, error) { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) - - msg := nl.NewIfInfomsg(family) - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY) - if err != nil { - return nil, err - } - - var res []XfrmPolicy - for _, m := range msgs { - msg := nl.DeserializeXfrmUserpolicyInfo(m) - - if family != FAMILY_ALL && family != int(msg.Sel.Family) { - continue - } - - var policy XfrmPolicy - - policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD) - policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS) - policy.Priority = int(msg.Priority) - policy.Index = int(msg.Index) - policy.Dir = Dir(msg.Dir) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.XFRMA_TMPL: - max := len(attr.Value) - for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { - var resTmpl XfrmPolicyTmpl - tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) - resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() - resTmpl.Src = tmpl.Saddr.ToIP() - resTmpl.Proto = Proto(tmpl.XfrmId.Proto) - resTmpl.Mode = Mode(tmpl.Mode) - resTmpl.Reqid = int(tmpl.Reqid) - policy.Tmpls = append(policy.Tmpls, resTmpl) - } - } - } - res = append(res, policy) - } - return res, nil -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go deleted file mode 100644 index 5b8f2df708e6ccb2c321f241acc6c33782d38a57..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go +++ /dev/null @@ -1,53 +0,0 @@ -package netlink - -import ( - "net" -) - -// XfrmStateAlgo represents the algorithm to use for the ipsec encryption. -type XfrmStateAlgo struct { - Name string - Key []byte - TruncateLen int // Auth only -} - -// EncapType is an enum representing an ipsec template direction. -type EncapType uint8 - -const ( - XFRM_ENCAP_ESPINUDP_NONIKE EncapType = iota + 1 - XFRM_ENCAP_ESPINUDP -) - -func (e EncapType) String() string { - switch e { - case XFRM_ENCAP_ESPINUDP_NONIKE: - return "espinudp-nonike" - case XFRM_ENCAP_ESPINUDP: - return "espinudp" - } - return "unknown" -} - -// XfrmEncap represents the encapsulation to use for the ipsec encryption. -type XfrmStateEncap struct { - Type EncapType - SrcPort int - DstPort int - OriginalAddress net.IP -} - -// XfrmState represents the state of an ipsec policy. It optionally -// contains an XfrmStateAlgo for encryption and one for authentication. -type XfrmState struct { - Dst net.IP - Src net.IP - Proto Proto - Mode Mode - Spi int - Reqid int - ReplayWindow int - Auth *XfrmStateAlgo - Crypt *XfrmStateAlgo - Encap *XfrmStateEncap -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go deleted file mode 100644 index 5f44ec8525e075c65a17ee3df842c5a3c6c965ef..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go +++ /dev/null @@ -1,181 +0,0 @@ -package netlink - -import ( - "fmt" - "syscall" - - "github.com/vishvananda/netlink/nl" -) - -func writeStateAlgo(a *XfrmStateAlgo) []byte { - algo := nl.XfrmAlgo{ - AlgKeyLen: uint32(len(a.Key) * 8), - AlgKey: a.Key, - } - end := len(a.Name) - if end > 64 { - end = 64 - } - copy(algo.AlgName[:end], a.Name) - return algo.Serialize() -} - -func writeStateAlgoAuth(a *XfrmStateAlgo) []byte { - algo := nl.XfrmAlgoAuth{ - AlgKeyLen: uint32(len(a.Key) * 8), - AlgTruncLen: uint32(a.TruncateLen), - AlgKey: a.Key, - } - end := len(a.Name) - if end > 64 { - end = 64 - } - copy(algo.AlgName[:end], a.Name) - return algo.Serialize() -} - -// XfrmStateAdd will add an xfrm state to the system. -// Equivalent to: `ip xfrm state add $state` -func XfrmStateAdd(state *XfrmState) error { - // A state with spi 0 can't be deleted so don't allow it to be set - if state.Spi == 0 { - return fmt.Errorf("Spi must be set when adding xfrm state.") - } - req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := &nl.XfrmUsersaInfo{} - msg.Family = uint16(nl.GetIPFamily(state.Dst)) - msg.Id.Daddr.FromIP(state.Dst) - msg.Saddr.FromIP(state.Src) - msg.Id.Proto = uint8(state.Proto) - msg.Mode = uint8(state.Mode) - msg.Id.Spi = nl.Swap32(uint32(state.Spi)) - msg.Reqid = uint32(state.Reqid) - msg.ReplayWindow = uint8(state.ReplayWindow) - msg.Lft.SoftByteLimit = nl.XFRM_INF - msg.Lft.HardByteLimit = nl.XFRM_INF - msg.Lft.SoftPacketLimit = nl.XFRM_INF - msg.Lft.HardPacketLimit = nl.XFRM_INF - req.AddData(msg) - - if state.Auth != nil { - out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth)) - req.AddData(out) - } - if state.Crypt != nil { - out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt)) - req.AddData(out) - } - if state.Encap != nil { - encapData := make([]byte, nl.SizeofXfrmEncapTmpl) - encap := nl.DeserializeXfrmEncapTmpl(encapData) - encap.EncapType = uint16(state.Encap.Type) - encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort)) - encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort)) - encap.EncapOa.FromIP(state.Encap.OriginalAddress) - out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData) - req.AddData(out) - } - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) - return err -} - -// XfrmStateDel will delete an xfrm state from the system. Note that -// the Algos are ignored when matching the state to delete. -// Equivalent to: `ip xfrm state del $state` -func XfrmStateDel(state *XfrmState) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK) - - msg := &nl.XfrmUsersaId{} - msg.Daddr.FromIP(state.Dst) - msg.Family = uint16(nl.GetIPFamily(state.Dst)) - msg.Proto = uint8(state.Proto) - msg.Spi = nl.Swap32(uint32(state.Spi)) - req.AddData(msg) - - saddr := nl.XfrmAddress{} - saddr.FromIP(state.Src) - srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize()) - - req.AddData(srcdata) - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) - return err -} - -// XfrmStateList gets a list of xfrm states in the system. -// Equivalent to: `ip xfrm state show`. -// The list can be filtered by ip family. -func XfrmStateList(family int) ([]XfrmState, error) { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) - - msg := nl.NewIfInfomsg(family) - req.AddData(msg) - - msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) - if err != nil { - return nil, err - } - - var res []XfrmState - for _, m := range msgs { - msg := nl.DeserializeXfrmUsersaInfo(m) - - if family != FAMILY_ALL && family != int(msg.Family) { - continue - } - - var state XfrmState - - state.Dst = msg.Id.Daddr.ToIP() - state.Src = msg.Saddr.ToIP() - state.Proto = Proto(msg.Id.Proto) - state.Mode = Mode(msg.Mode) - state.Spi = int(nl.Swap32(msg.Id.Spi)) - state.Reqid = int(msg.Reqid) - state.ReplayWindow = int(msg.ReplayWindow) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: - var resAlgo *XfrmStateAlgo - if attr.Attr.Type == nl.XFRMA_ALG_AUTH { - if state.Auth == nil { - state.Auth = new(XfrmStateAlgo) - } - resAlgo = state.Auth - } else { - state.Crypt = new(XfrmStateAlgo) - resAlgo = state.Crypt - } - algo := nl.DeserializeXfrmAlgo(attr.Value[:]) - (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) - (*resAlgo).Key = algo.AlgKey - case nl.XFRMA_ALG_AUTH_TRUNC: - if state.Auth == nil { - state.Auth = new(XfrmStateAlgo) - } - algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) - state.Auth.Name = nl.BytesToString(algo.AlgName[:]) - state.Auth.Key = algo.AlgKey - state.Auth.TruncateLen = int(algo.AlgTruncLen) - case nl.XFRMA_ENCAP: - encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) - state.Encap = new(XfrmStateEncap) - state.Encap.Type = EncapType(encap.EncapType) - state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) - state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) - state.Encap.OriginalAddress = encap.EncapOa.ToIP() - } - - } - res = append(res, state) - } - return res, nil -} diff --git a/vendor/github.com/opencontainers/runc/checkpoint.go b/vendor/github.com/opencontainers/runc/checkpoint.go index 81de35a8c1c526f2b255cd32e112c413544f5e77..ae01ea3c0764dacb643873d0451b5bb6f21330c4 100644 --- a/vendor/github.com/opencontainers/runc/checkpoint.go +++ b/vendor/github.com/opencontainers/runc/checkpoint.go @@ -4,11 +4,17 @@ package main import ( "fmt" + "os" "strconv" "strings" - "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + + "golang.org/x/sys/unix" ) var checkpointCommand = cli.Command{ @@ -22,27 +28,49 @@ checkpointed.`, Flags: []cli.Flag{ cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, + cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"}, cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, + cli.BoolFlag{Name: "lazy-pages", Usage: "use userfaultfd to lazily restore memory pages"}, + cli.StringFlag{Name: "status-fd", Value: "", Usage: "criu writes \\0 to this FD once lazy-pages is ready"}, cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"}, - cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'."}, + cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"}, + cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'"}, + cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"}, + cli.BoolFlag{Name: "auto-dedup", Usage: "enable auto deduplication of memory images"}, }, - Action: func(context *cli.Context) { + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + // XXX: Currently this is untested with rootless containers. + if os.Geteuid() != 0 || system.RunningInUserNS() { + logrus.Warn("runc checkpoint is untested with rootless containers") + } + container, err := getContainer(context) if err != nil { - fatal(err) + return err + } + status, err := container.Status() + if err != nil { + return err + } + if status == libcontainer.Created || status == libcontainer.Stopped { + fatalf("Container cannot be checkpointed in %s state", status.String()) } defer destroy(container) options := criuOptions(context) // these are the mandatory criu options for a container setPageServer(context, options) setManageCgroupsMode(context, options) - if err := container.Checkpoint(options); err != nil { - fatal(err) + if err := setEmptyNsMask(context, options); err != nil { + return err } + return container.Checkpoint(options) }, } @@ -87,3 +115,23 @@ func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) } } } + +var namespaceMapping = map[specs.LinuxNamespaceType]int{ + specs.NetworkNamespace: unix.CLONE_NEWNET, +} + +func setEmptyNsMask(context *cli.Context, options *libcontainer.CriuOpts) error { + /* Runc doesn't manage network devices and their configuration */ + nsmask := unix.CLONE_NEWNET + + for _, ns := range context.StringSlice("empty-ns") { + f, exists := namespaceMapping[specs.LinuxNamespaceType(ns)] + if !exists { + return fmt.Errorf("namespace %q is not supported", ns) + } + nsmask |= f + } + + options.EmptyNs = uint32(nsmask) + return nil +} diff --git a/vendor/github.com/opencontainers/runc/contrib/cmd/recvtty/recvtty.go b/vendor/github.com/opencontainers/runc/contrib/cmd/recvtty/recvtty.go new file mode 100644 index 0000000000000000000000000000000000000000..a658b8d20202af5c8ad83150ee9ce3703cc6a514 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/contrib/cmd/recvtty/recvtty.go @@ -0,0 +1,238 @@ +/* + * Copyright 2016 SUSE LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "io" + "io/ioutil" + "net" + "os" + "strings" + + "github.com/containerd/console" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/urfave/cli" +) + +// version will be populated by the Makefile, read from +// VERSION file of the source code. +var version = "" + +// gitCommit will be the hash that the binary was built from +// and will be populated by the Makefile +var gitCommit = "" + +const ( + usage = `Open Container Initiative contrib/cmd/recvtty + +recvtty is a reference implementation of a consumer of runC's --console-socket +API. It has two main modes of operation: + + * single: Only permit one terminal to be sent to the socket, which is + then hooked up to the stdio of the recvtty process. This is useful + for rudimentary shell management of a container. + + * null: Permit as many terminals to be sent to the socket, but they + are read to /dev/null. This is used for testing, and imitates the + old runC API's --console=/dev/pts/ptmx hack which would allow for a + similar trick. This is probably not what you want to use, unless + you're doing something like our bats integration tests. + +To use recvtty, just specify a socket path at which you want to receive +terminals: + + $ recvtty [--mode <single|null>] socket.sock +` +) + +func bail(err error) { + fmt.Fprintf(os.Stderr, "[recvtty] fatal error: %v\n", err) + os.Exit(1) +} + +func handleSingle(path string) error { + // Open a socket. + ln, err := net.Listen("unix", path) + if err != nil { + return err + } + defer ln.Close() + + // We only accept a single connection, since we can only really have + // one reader for os.Stdin. Plus this is all a PoC. + conn, err := ln.Accept() + if err != nil { + return err + } + defer conn.Close() + + // Close ln, to allow for other instances to take over. + ln.Close() + + // Get the fd of the connection. + unixconn, ok := conn.(*net.UnixConn) + if !ok { + return fmt.Errorf("failed to cast to unixconn") + } + + socket, err := unixconn.File() + if err != nil { + return err + } + defer socket.Close() + + // Get the master file descriptor from runC. + master, err := utils.RecvFd(socket) + if err != nil { + return err + } + c, err := console.ConsoleFromFile(master) + if err != nil { + return err + } + console.ClearONLCR(c.Fd()) + + // Copy from our stdio to the master fd. + quitChan := make(chan struct{}) + go func() { + io.Copy(os.Stdout, c) + quitChan <- struct{}{} + }() + go func() { + io.Copy(c, os.Stdin) + quitChan <- struct{}{} + }() + + // Only close the master fd once we've stopped copying. + <-quitChan + c.Close() + return nil +} + +func handleNull(path string) error { + // Open a socket. + ln, err := net.Listen("unix", path) + if err != nil { + return err + } + defer ln.Close() + + // As opposed to handleSingle we accept as many connections as we get, but + // we don't interact with Stdin at all (and we copy stdout to /dev/null). + for { + conn, err := ln.Accept() + if err != nil { + return err + } + go func(conn net.Conn) { + // Don't leave references lying around. + defer conn.Close() + + // Get the fd of the connection. + unixconn, ok := conn.(*net.UnixConn) + if !ok { + return + } + + socket, err := unixconn.File() + if err != nil { + return + } + defer socket.Close() + + // Get the master file descriptor from runC. + master, err := utils.RecvFd(socket) + if err != nil { + return + } + + // Just do a dumb copy to /dev/null. + devnull, err := os.OpenFile("/dev/null", os.O_RDWR, 0) + if err != nil { + // TODO: Handle this nicely. + return + } + + io.Copy(devnull, master) + devnull.Close() + }(conn) + } +} + +func main() { + app := cli.NewApp() + app.Name = "recvtty" + app.Usage = usage + + // Set version to be the same as runC. + var v []string + if version != "" { + v = append(v, version) + } + if gitCommit != "" { + v = append(v, fmt.Sprintf("commit: %s", gitCommit)) + } + app.Version = strings.Join(v, "\n") + + // Set the flags. + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "mode, m", + Value: "single", + Usage: "Mode of operation (single or null)", + }, + cli.StringFlag{ + Name: "pid-file", + Value: "", + Usage: "Path to write daemon process ID to", + }, + } + + app.Action = func(ctx *cli.Context) error { + args := ctx.Args() + if len(args) != 1 { + return fmt.Errorf("need to specify a single socket path") + } + path := ctx.Args()[0] + + pidPath := ctx.String("pid-file") + if pidPath != "" { + pid := fmt.Sprintf("%d\n", os.Getpid()) + if err := ioutil.WriteFile(pidPath, []byte(pid), 0644); err != nil { + return err + } + } + + switch ctx.String("mode") { + case "single": + if err := handleSingle(path); err != nil { + return err + } + case "null": + if err := handleNull(path); err != nil { + return err + } + default: + return fmt.Errorf("need to select a valid mode: %s", ctx.String("mode")) + } + return nil + } + if err := app.Run(os.Args); err != nil { + bail(err) + } +} diff --git a/vendor/github.com/opencontainers/runc/create.go b/vendor/github.com/opencontainers/runc/create.go new file mode 100644 index 0000000000000000000000000000000000000000..5f3ac60958e66b90471330df95d9ef7b2ad21ed1 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/create.go @@ -0,0 +1,74 @@ +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +var createCommand = cli.Command{ + Name: "create", + Usage: "create a container", + ArgsUsage: `<container-id> + +Where "<container-id>" is your name for the instance of the container that you +are starting. The name you provide for the container instance must be unique on +your host.`, + Description: `The create command creates an instance of a container for a bundle. The bundle +is a directory with a specification file named "` + specConfig + `" and a root +filesystem. + +The specification file includes an args parameter. The args parameter is used +to specify command(s) that get run when the container is started. To change the +command(s) that get executed on start, edit the args parameter of the spec. See +"runc spec --help" for more explanation.`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "bundle, b", + Value: "", + Usage: `path to the root of the bundle directory, defaults to the current directory`, + }, + cli.StringFlag{ + Name: "console-socket", + Value: "", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", + }, + cli.StringFlag{ + Name: "pid-file", + Value: "", + Usage: "specify the file to write the process id to", + }, + cli.BoolFlag{ + Name: "no-pivot", + Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", + }, + cli.BoolFlag{ + Name: "no-new-keyring", + Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", + }, + cli.IntFlag{ + Name: "preserve-fds", + Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err + } + spec, err := setupSpec(context) + if err != nil { + return err + } + status, err := startContainer(context, spec, CT_ACT_CREATE, nil) + if err != nil { + return err + } + // exit with the container's exit status so any external supervisor is + // notified of the exit with the correct exit status. + os.Exit(status) + return nil + }, +} diff --git a/vendor/github.com/opencontainers/runc/delete.go b/vendor/github.com/opencontainers/runc/delete.go index 4f46564e14040f503634e957073f3d8c047bee05..fb6f38eddf71239ddeac72d7d80d6d81411610fb 100644 --- a/vendor/github.com/opencontainers/runc/delete.go +++ b/vendor/github.com/opencontainers/runc/delete.go @@ -1,24 +1,89 @@ +// +build !solaris + package main -import "github.com/codegangsta/cli" +import ( + "fmt" + "os" + "path/filepath" + "syscall" + "time" + + "github.com/opencontainers/runc/libcontainer" + "github.com/urfave/cli" + + "golang.org/x/sys/unix" +) + +func killContainer(container libcontainer.Container) error { + _ = container.Signal(unix.SIGKILL, false) + for i := 0; i < 100; i++ { + time.Sleep(100 * time.Millisecond) + if err := container.Signal(syscall.Signal(0), false); err != nil { + destroy(container) + return nil + } + } + return fmt.Errorf("container init still running") +} var deleteCommand = cli.Command{ Name: "delete", - Usage: "delete any resources held by the container often used with detached containers", + Usage: "delete any resources held by the container often used with detached container", ArgsUsage: `<container-id> Where "<container-id>" is the name for the instance of the container. - + +EXAMPLE: For example, if the container id is "ubuntu01" and runc list currently shows the -status of "ubuntu01" as "destroyed" the following will delete resources held for -"ubuntu01" removing "ubuntu01" from the runc list of containers: - +status of "ubuntu01" as "stopped" the following will delete resources held for +"ubuntu01" removing "ubuntu01" from the runc list of containers: + # runc delete ubuntu01`, - Action: func(context *cli.Context) { + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "force, f", + Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)", + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + + id := context.Args().First() + force := context.Bool("force") container, err := getContainer(context) if err != nil { - fatal(err) + if lerr, ok := err.(libcontainer.Error); ok && lerr.Code() == libcontainer.ContainerNotExists { + // if there was an aborted start or something of the sort then the container's directory could exist but + // libcontainer does not see it because the state.json file inside that directory was never created. + path := filepath.Join(context.GlobalString("root"), id) + if e := os.RemoveAll(path); e != nil { + fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e) + } + if force { + return nil + } + } + return err } - destroy(container) + s, err := container.Status() + if err != nil { + return err + } + switch s { + case libcontainer.Stopped: + destroy(container) + case libcontainer.Created: + return killContainer(container) + default: + if force { + return killContainer(container) + } + return fmt.Errorf("cannot delete container %s that is not stopped: %s\n", id, s) + } + + return nil }, } diff --git a/vendor/github.com/opencontainers/runc/events.go b/vendor/github.com/opencontainers/runc/events.go index e741480af4bf73ce4e451fcee518911be10d6df0..cfe369e1ecdf98cafc4a2cfbc283b35160f5bd3e 100644 --- a/vendor/github.com/opencontainers/runc/events.go +++ b/vendor/github.com/opencontainers/runc/events.go @@ -4,13 +4,17 @@ package main import ( "encoding/json" + "fmt" "os" "sync" "time" - "github.com/sirupsen/logrus" - "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/intelrdt" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" ) // event struct for encoding the event data to json. @@ -20,9 +24,116 @@ type event struct { Data interface{} `json:"data,omitempty"` } +// stats is the runc specific stats structure for stability when encoding and decoding stats. +type stats struct { + CPU cpu `json:"cpu"` + Memory memory `json:"memory"` + Pids pids `json:"pids"` + Blkio blkio `json:"blkio"` + Hugetlb map[string]hugetlb `json:"hugetlb"` + IntelRdt intelRdt `json:"intel_rdt"` +} + +type hugetlb struct { + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type blkioEntry struct { + Major uint64 `json:"major,omitempty"` + Minor uint64 `json:"minor,omitempty"` + Op string `json:"op,omitempty"` + Value uint64 `json:"value,omitempty"` +} + +type blkio struct { + IoServiceBytesRecursive []blkioEntry `json:"ioServiceBytesRecursive,omitempty"` + IoServicedRecursive []blkioEntry `json:"ioServicedRecursive,omitempty"` + IoQueuedRecursive []blkioEntry `json:"ioQueueRecursive,omitempty"` + IoServiceTimeRecursive []blkioEntry `json:"ioServiceTimeRecursive,omitempty"` + IoWaitTimeRecursive []blkioEntry `json:"ioWaitTimeRecursive,omitempty"` + IoMergedRecursive []blkioEntry `json:"ioMergedRecursive,omitempty"` + IoTimeRecursive []blkioEntry `json:"ioTimeRecursive,omitempty"` + SectorsRecursive []blkioEntry `json:"sectorsRecursive,omitempty"` +} + +type pids struct { + Current uint64 `json:"current,omitempty"` + Limit uint64 `json:"limit,omitempty"` +} + +type throttling struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` + ThrottledTime uint64 `json:"throttledTime,omitempty"` +} + +type cpuUsage struct { + // Units: nanoseconds. + Total uint64 `json:"total,omitempty"` + Percpu []uint64 `json:"percpu,omitempty"` + Kernel uint64 `json:"kernel"` + User uint64 `json:"user"` +} + +type cpu struct { + Usage cpuUsage `json:"usage,omitempty"` + Throttling throttling `json:"throttling,omitempty"` +} + +type memoryEntry struct { + Limit uint64 `json:"limit"` + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type memory struct { + Cache uint64 `json:"cache,omitempty"` + Usage memoryEntry `json:"usage,omitempty"` + Swap memoryEntry `json:"swap,omitempty"` + Kernel memoryEntry `json:"kernel,omitempty"` + KernelTCP memoryEntry `json:"kernelTCP,omitempty"` + Raw map[string]uint64 `json:"raw,omitempty"` +} + +type l3CacheInfo struct { + CbmMask string `json:"cbm_mask,omitempty"` + MinCbmBits uint64 `json:"min_cbm_bits,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type memBwInfo struct { + BandwidthGran uint64 `json:"bandwidth_gran,omitempty"` + DelayLinear uint64 `json:"delay_linear,omitempty"` + MinBandwidth uint64 `json:"min_bandwidth,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type intelRdt struct { + // The read-only L3 cache information + L3CacheInfo *l3CacheInfo `json:"l3_cache_info,omitempty"` + + // The read-only L3 cache schema in root + L3CacheSchemaRoot string `json:"l3_cache_schema_root,omitempty"` + + // The L3 cache schema in 'container_id' group + L3CacheSchema string `json:"l3_cache_schema,omitempty"` + + // The read-only memory bandwidth information + MemBwInfo *memBwInfo `json:"mem_bw_info,omitempty"` + + // The read-only memory bandwidth schema in root + MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"` + + // The memory bandwidth schema in 'container_id' group + MemBwSchema string `json:"mem_bw_schema,omitempty"` +} + var eventsCommand = cli.Command{ Name: "events", - Usage: "display container events such as OOM notifications, cpu, memory, IO and network stats", + Usage: "display container events such as OOM notifications, cpu, memory, and IO usage statistics", ArgsUsage: `<container-id> Where "<container-id>" is the name for the instance of the container.`, @@ -32,10 +143,24 @@ information is displayed once every 5 seconds.`, cli.DurationFlag{Name: "interval", Value: 5 * time.Second, Usage: "set the stats collection interval"}, cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"}, }, - Action: func(context *cli.Context) { + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { - fatal(err) + return err + } + duration := context.Duration("interval") + if duration <= 0 { + return fmt.Errorf("duration interval must be greater than 0") + } + status, err := container.Status() + if err != nil { + return err + } + if status == libcontainer.Stopped { + return fmt.Errorf("container with id %s is not running", container.ID()) } var ( stats = make(chan *libcontainer.Stats, 1) @@ -55,12 +180,12 @@ information is displayed once every 5 seconds.`, if context.Bool("stats") { s, err := container.Stats() if err != nil { - fatal(err) + return err } - events <- &event{Type: "stats", ID: container.ID(), Data: s} + events <- &event{Type: "stats", ID: container.ID(), Data: convertLibcontainerStats(s)} close(events) group.Wait() - return + return nil } go func() { for range time.Tick(context.Duration("interval")) { @@ -74,7 +199,7 @@ information is displayed once every 5 seconds.`, }() n, err := container.NotifyOOM() if err != nil { - fatal(err) + return err } for { select { @@ -88,7 +213,7 @@ information is displayed once every 5 seconds.`, n = nil } case s := <-stats: - events <- &event{Type: "stats", ID: container.ID(), Data: s} + events <- &event{Type: "stats", ID: container.ID(), Data: convertLibcontainerStats(s)} } if n == nil { close(events) @@ -96,5 +221,107 @@ information is displayed once every 5 seconds.`, } } group.Wait() + return nil }, } + +func convertLibcontainerStats(ls *libcontainer.Stats) *stats { + cg := ls.CgroupStats + if cg == nil { + return nil + } + var s stats + s.Pids.Current = cg.PidsStats.Current + s.Pids.Limit = cg.PidsStats.Limit + + s.CPU.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode + s.CPU.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode + s.CPU.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage + s.CPU.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage + s.CPU.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods + s.CPU.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods + s.CPU.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime + + s.Memory.Cache = cg.MemoryStats.Cache + s.Memory.Kernel = convertMemoryEntry(cg.MemoryStats.KernelUsage) + s.Memory.KernelTCP = convertMemoryEntry(cg.MemoryStats.KernelTCPUsage) + s.Memory.Swap = convertMemoryEntry(cg.MemoryStats.SwapUsage) + s.Memory.Usage = convertMemoryEntry(cg.MemoryStats.Usage) + s.Memory.Raw = cg.MemoryStats.Stats + + s.Blkio.IoServiceBytesRecursive = convertBlkioEntry(cg.BlkioStats.IoServiceBytesRecursive) + s.Blkio.IoServicedRecursive = convertBlkioEntry(cg.BlkioStats.IoServicedRecursive) + s.Blkio.IoQueuedRecursive = convertBlkioEntry(cg.BlkioStats.IoQueuedRecursive) + s.Blkio.IoServiceTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoServiceTimeRecursive) + s.Blkio.IoWaitTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoWaitTimeRecursive) + s.Blkio.IoMergedRecursive = convertBlkioEntry(cg.BlkioStats.IoMergedRecursive) + s.Blkio.IoTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoTimeRecursive) + s.Blkio.SectorsRecursive = convertBlkioEntry(cg.BlkioStats.SectorsRecursive) + + s.Hugetlb = make(map[string]hugetlb) + for k, v := range cg.HugetlbStats { + s.Hugetlb[k] = convertHugtlb(v) + } + + if is := ls.IntelRdtStats; is != nil { + if intelrdt.IsCatEnabled() { + s.IntelRdt.L3CacheInfo = convertL3CacheInfo(is.L3CacheInfo) + s.IntelRdt.L3CacheSchemaRoot = is.L3CacheSchemaRoot + s.IntelRdt.L3CacheSchema = is.L3CacheSchema + } + if intelrdt.IsMbaEnabled() { + s.IntelRdt.MemBwInfo = convertMemBwInfo(is.MemBwInfo) + s.IntelRdt.MemBwSchemaRoot = is.MemBwSchemaRoot + s.IntelRdt.MemBwSchema = is.MemBwSchema + } + } + + return &s +} + +func convertHugtlb(c cgroups.HugetlbStats) hugetlb { + return hugetlb{ + Usage: c.Usage, + Max: c.MaxUsage, + Failcnt: c.Failcnt, + } +} + +func convertMemoryEntry(c cgroups.MemoryData) memoryEntry { + return memoryEntry{ + Limit: c.Limit, + Usage: c.Usage, + Max: c.MaxUsage, + Failcnt: c.Failcnt, + } +} + +func convertBlkioEntry(c []cgroups.BlkioStatEntry) []blkioEntry { + var out []blkioEntry + for _, e := range c { + out = append(out, blkioEntry{ + Major: e.Major, + Minor: e.Minor, + Op: e.Op, + Value: e.Value, + }) + } + return out +} + +func convertL3CacheInfo(i *intelrdt.L3CacheInfo) *l3CacheInfo { + return &l3CacheInfo{ + CbmMask: i.CbmMask, + MinCbmBits: i.MinCbmBits, + NumClosids: i.NumClosids, + } +} + +func convertMemBwInfo(i *intelrdt.MemBwInfo) *memBwInfo { + return &memBwInfo{ + BandwidthGran: i.BandwidthGran, + DelayLinear: i.DelayLinear, + MinBandwidth: i.MinBandwidth, + NumClosids: i.NumClosids, + } +} diff --git a/vendor/github.com/opencontainers/runc/exec.go b/vendor/github.com/opencontainers/runc/exec.go index 0f7fe8819c321fe53a2cf5aca90280476c74dfe7..ae8e60e4263a7db844204d4412fedb4fa06fb686 100644 --- a/vendor/github.com/opencontainers/runc/exec.go +++ b/vendor/github.com/opencontainers/runc/exec.go @@ -9,26 +9,30 @@ import ( "strconv" "strings" - "github.com/codegangsta/cli" - "github.com/opencontainers/specs/specs-go" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/urfave/cli" ) var execCommand = cli.Command{ Name: "exec", Usage: "execute new process inside the container", - ArgsUsage: `<container-id> <container command> + ArgsUsage: `<container-id> <command> [command options] || -p process.json <container-id> Where "<container-id>" is the name for the instance of the container and -"<container command>" is the command to be executed in the container. +"<command>" is the command to be executed in the container. +"<command>" can't be empty unless a "-p" flag provided. +EXAMPLE: For example, if the container is configured to run the linux ps command the following will output a list of processes running in the container: - + # runc exec <container-id> ps`, Flags: []cli.Flag{ cli.StringFlag{ - Name: "console", - Usage: "specify the pty slave path for use with the container", + Name: "console-socket", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", }, cli.StringFlag{ Name: "cwd", @@ -46,6 +50,10 @@ following will output a list of processes running in the container: Name: "user, u", Usage: "UID (format: <uid>[:<gid>])", }, + cli.Int64SliceFlag{ + Name: "additional-gids, g", + Usage: "additional gids", + }, cli.StringFlag{ Name: "process, p", Usage: "path to the process.json", @@ -76,17 +84,26 @@ following will output a list of processes running in the container: Value: &cli.StringSlice{}, Usage: "add a capability to the bounding set for the process", }, + cli.BoolFlag{ + Name: "no-subreaper", + Usage: "disable the use of the subreaper used to reap reparented processes", + Hidden: true, + }, }, - Action: func(context *cli.Context) { - if os.Geteuid() != 0 { - fatalf("runc should be run as root") + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err } status, err := execProcess(context) - if err != nil { - fatalf("exec failed: %v", err) + if err == nil { + os.Exit(status) } - os.Exit(status) + return fmt.Errorf("exec failed: %v", err) }, + SkipArgReorder: true, } func execProcess(context *cli.Context) (int, error) { @@ -94,17 +111,38 @@ func execProcess(context *cli.Context) (int, error) { if err != nil { return -1, err } + status, err := container.Status() + if err != nil { + return -1, err + } + if status == libcontainer.Stopped { + return -1, fmt.Errorf("cannot exec a container that has stopped") + } + path := context.String("process") + if path == "" && len(context.Args()) == 1 { + return -1, fmt.Errorf("process args cannot be empty") + } detach := context.Bool("detach") state, err := container.State() if err != nil { return -1, err } - bundle := searchLabels(state.Config.Labels, "bundle") + bundle := utils.SearchLabels(state.Config.Labels, "bundle") p, err := getProcess(context, bundle) if err != nil { return -1, err } - return runProcess(container, p, nil, context.String("console"), context.String("pid-file"), detach) + r := &runner{ + enableSubreaper: false, + shouldDestroy: false, + container: container, + consoleSocket: context.String("console-socket"), + detach: detach, + pidFile: context.String("pid-file"), + action: CT_ACT_RUN, + init: false, + } + return r.run(p) } func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { @@ -118,7 +156,7 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { if err := json.NewDecoder(f).Decode(&p); err != nil { return nil, err } - return &p, nil + return &p, validateProcessSpec(&p) } // process via cli flags if err := os.Chdir(bundle); err != nil { @@ -141,12 +179,17 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { p.SelinuxLabel = l } if caps := context.StringSlice("cap"); len(caps) > 0 { - p.Capabilities = caps + for _, c := range caps { + p.Capabilities.Bounding = append(p.Capabilities.Bounding, c) + p.Capabilities.Inheritable = append(p.Capabilities.Inheritable, c) + p.Capabilities.Effective = append(p.Capabilities.Effective, c) + p.Capabilities.Permitted = append(p.Capabilities.Permitted, c) + p.Capabilities.Ambient = append(p.Capabilities.Ambient, c) + } } // append the passed env variables - for _, e := range context.StringSlice("env") { - p.Env = append(p.Env, e) - } + p.Env = append(p.Env, context.StringSlice("env")...) + // set the tty if context.IsSet("tty") { p.Terminal = context.Bool("tty") @@ -170,5 +213,11 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { } p.User.UID = uint32(uid) } - return &p, nil + for _, gid := range context.Int64Slice("additional-gids") { + if gid < 0 { + return nil, fmt.Errorf("additional-gids must be a positive number %d", gid) + } + p.User.AdditionalGids = append(p.User.AdditionalGids, uint32(gid)) + } + return p, nil } diff --git a/vendor/github.com/opencontainers/runc/init.go b/vendor/github.com/opencontainers/runc/init.go new file mode 100644 index 0000000000000000000000000000000000000000..c8f4531923df822e5c7c96eef3c214a5e8f4dc68 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/init.go @@ -0,0 +1,31 @@ +package main + +import ( + "os" + "runtime" + + "github.com/opencontainers/runc/libcontainer" + _ "github.com/opencontainers/runc/libcontainer/nsenter" + "github.com/urfave/cli" +) + +func init() { + if len(os.Args) > 1 && os.Args[1] == "init" { + runtime.GOMAXPROCS(1) + runtime.LockOSThread() + } +} + +var initCommand = cli.Command{ + Name: "init", + Usage: `initialize the namespaces and launch the process (do not call it outside of runc)`, + Action: func(context *cli.Context) error { + factory, _ := libcontainer.New("") + if err := factory.StartInitialization(); err != nil { + // as the error is sent back to the parent there is no need to log + // or write it to stderr because the parent process will handle this + os.Exit(1) + } + panic("libcontainer: container init failed to exec") + }, +} diff --git a/vendor/github.com/opencontainers/runc/kill.go b/vendor/github.com/opencontainers/runc/kill.go index 3da8aaf6dbb69a1b47222ec821dfe872536c71c3..c2d7929694122063d79f5963d04abb56ed665c21 100644 --- a/vendor/github.com/opencontainers/runc/kill.go +++ b/vendor/github.com/opencontainers/runc/kill.go @@ -8,63 +8,38 @@ import ( "strings" "syscall" - "github.com/codegangsta/cli" + "github.com/urfave/cli" ) -var signalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUS": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CLD": syscall.SIGCLD, - "CONT": syscall.SIGCONT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "PIPE": syscall.SIGPIPE, - "POLL": syscall.SIGPOLL, - "PROF": syscall.SIGPROF, - "PWR": syscall.SIGPWR, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STKFLT": syscall.SIGSTKFLT, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "UNUSED": syscall.SIGUNUSED, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} - var killCommand = cli.Command{ Name: "kill", Usage: "kill sends the specified signal (default: SIGTERM) to the container's init process", - ArgsUsage: `<container-id> <signal> + ArgsUsage: `<container-id> [signal] Where "<container-id>" is the name for the instance of the container and -"<signal>" is the signal to be sent to the init process. - +"[signal]" is the signal to be sent to the init process. + +EXAMPLE: For example, if the container id is "ubuntu01" the following will send a "KILL" signal to the init process of the "ubuntu01" container: # runc kill ubuntu01 KILL`, - Action: func(context *cli.Context) { + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "send the specified signal to all processes inside the container", + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + if err := checkArgs(context, 2, maxArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { - fatal(err) + return err } sigstr := context.Args().Get(1) @@ -74,12 +49,9 @@ signal to the init process of the "ubuntu01" container: signal, err := parseSignal(sigstr) if err != nil { - fatal(err) - } - - if err := container.Signal(signal); err != nil { - fatal(err) + return err } + return container.Signal(signal, context.Bool("all")) }, } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go index 22c17f5272c7c5fdc80679e821fc749578f327ed..7fff0627fa1b3d9d4a0f018e7ece22953c1f0129 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go @@ -2,14 +2,10 @@ package apparmor -// #cgo LDFLAGS: -lapparmor -// #include <sys/apparmor.h> -// #include <stdlib.h> -import "C" import ( + "fmt" "io/ioutil" "os" - "unsafe" ) // IsEnabled returns true if apparmor is enabled for the host. @@ -23,16 +19,36 @@ func IsEnabled() bool { return false } +func setprocattr(attr, value string) error { + // Under AppArmor you can only change your own attr, so use /proc/self/ + // instead of /proc/<tid>/ like libapparmor does + path := fmt.Sprintf("/proc/self/attr/%s", attr) + + f, err := os.OpenFile(path, os.O_WRONLY, 0) + if err != nil { + return err + } + defer f.Close() + + _, err = fmt.Fprintf(f, "%s", value) + return err +} + +// changeOnExec reimplements aa_change_onexec from libapparmor in Go +func changeOnExec(name string) error { + value := "exec " + name + if err := setprocattr("exec", value); err != nil { + return fmt.Errorf("apparmor failed to apply profile: %s", err) + } + return nil +} + // ApplyProfile will apply the profile with the specified name to the process after // the next exec. func ApplyProfile(name string) error { if name == "" { return nil } - cName := C.CString(name) - defer C.free(unsafe.Pointer(cName)) - if _, err := C.aa_change_onexec(cName); err != nil { - return err - } - return nil + + return changeOnExec(name) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go index 4eda56d1abb830c73f91586639b6a7910c303f56..7c66f5725803fd04564294470cb5b9c9509e199b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/capabilities_linux.go @@ -4,13 +4,13 @@ package libcontainer import ( "fmt" - "os" "strings" + "github.com/opencontainers/runc/libcontainer/configs" "github.com/syndtr/gocapability/capability" ) -const allCapabilityTypes = capability.CAPS | capability.BOUNDS +const allCapabilityTypes = capability.CAPS | capability.BOUNDS | capability.AMBS var capabilityMap map[string]capability.Cap @@ -30,40 +30,84 @@ func init() { } } -func newCapWhitelist(caps []string) (*whitelist, error) { - l := []capability.Cap{} - for _, c := range caps { +func newContainerCapList(capConfig *configs.Capabilities) (*containerCapabilities, error) { + bounding := []capability.Cap{} + for _, c := range capConfig.Bounding { v, ok := capabilityMap[c] if !ok { return nil, fmt.Errorf("unknown capability %q", c) } - l = append(l, v) + bounding = append(bounding, v) } - pid, err := capability.NewPid(os.Getpid()) + effective := []capability.Cap{} + for _, c := range capConfig.Effective { + v, ok := capabilityMap[c] + if !ok { + return nil, fmt.Errorf("unknown capability %q", c) + } + effective = append(effective, v) + } + inheritable := []capability.Cap{} + for _, c := range capConfig.Inheritable { + v, ok := capabilityMap[c] + if !ok { + return nil, fmt.Errorf("unknown capability %q", c) + } + inheritable = append(inheritable, v) + } + permitted := []capability.Cap{} + for _, c := range capConfig.Permitted { + v, ok := capabilityMap[c] + if !ok { + return nil, fmt.Errorf("unknown capability %q", c) + } + permitted = append(permitted, v) + } + ambient := []capability.Cap{} + for _, c := range capConfig.Ambient { + v, ok := capabilityMap[c] + if !ok { + return nil, fmt.Errorf("unknown capability %q", c) + } + ambient = append(ambient, v) + } + pid, err := capability.NewPid(0) if err != nil { return nil, err } - return &whitelist{ - keep: l, - pid: pid, + return &containerCapabilities{ + bounding: bounding, + effective: effective, + inheritable: inheritable, + permitted: permitted, + ambient: ambient, + pid: pid, }, nil } -type whitelist struct { - pid capability.Capabilities - keep []capability.Cap +type containerCapabilities struct { + pid capability.Capabilities + bounding []capability.Cap + effective []capability.Cap + inheritable []capability.Cap + permitted []capability.Cap + ambient []capability.Cap } -// dropBoundingSet drops the capability bounding set to those specified in the whitelist. -func (w *whitelist) dropBoundingSet() error { - w.pid.Clear(capability.BOUNDS) - w.pid.Set(capability.BOUNDS, w.keep...) - return w.pid.Apply(capability.BOUNDS) +// ApplyBoundingSet sets the capability bounding set to those specified in the whitelist. +func (c *containerCapabilities) ApplyBoundingSet() error { + c.pid.Clear(capability.BOUNDS) + c.pid.Set(capability.BOUNDS, c.bounding...) + return c.pid.Apply(capability.BOUNDS) } -// drop drops all capabilities for the current process except those specified in the whitelist. -func (w *whitelist) drop() error { - w.pid.Clear(allCapabilityTypes) - w.pid.Set(allCapabilityTypes, w.keep...) - return w.pid.Apply(allCapabilityTypes) +// Apply sets all the capabilities for the current process in the config. +func (c *containerCapabilities) ApplyCaps() error { + c.pid.Clear(allCapabilityTypes) + c.pid.Set(capability.BOUNDS, c.bounding...) + c.pid.Set(capability.PERMITTED, c.permitted...) + c.pid.Set(capability.INHERITABLE, c.inheritable...) + c.pid.Set(capability.EFFECTIVE, c.effective...) + c.pid.Set(capability.AMBIENT, c.ambient...) + return c.pid.Apply(allCapabilityTypes) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go index c8f7796567b9400b4f4ec22c46aca7fcb6a84aff..25ff5158933ac86865f62cd92e9974221f98a1d3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go @@ -9,7 +9,7 @@ import ( ) type Manager interface { - // Apply cgroup configuration to the process with the specified pid + // Applies cgroup configuration to the process with the specified pid Apply(pid int) error // Returns the PIDs inside the cgroup set @@ -27,9 +27,9 @@ type Manager interface { // Destroys the cgroup set Destroy() error - // NewCgroupManager() and LoadCgroupManager() require following attributes: + // The option func SystemdCgroups() and Cgroupfs() require following attributes: // Paths map[string]string - // Cgroups *cgroups.Cgroup + // Cgroups *configs.Cgroup // Paths maps cgroup subsystem to path at which it is mounted. // Cgroups specifies specific cgroup settings for the various subsystems @@ -37,7 +37,7 @@ type Manager interface { // restore the object later. GetPaths() map[string]string - // Set the cgroup as configured. + // Sets the cgroup as configured. Set(container *configs.Config) error } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go index 6def4ea54230dd2b2f3057ffa5b7406951c95eb8..f672ba27377b20aea4fda7e9b5cfd6e16c65ac02 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go @@ -3,18 +3,18 @@ package fs import ( - "errors" "fmt" "io" "io/ioutil" "os" "path/filepath" - "strconv" "sync" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" + "github.com/pkg/errors" + "golang.org/x/sys/unix" ) var ( @@ -33,11 +33,10 @@ var ( &FreezerGroup{}, &NameGroup{GroupName: "name=systemd", Join: true}, } - CgroupProcesses = "cgroup.procs" HugePageSizes, _ = cgroups.GetHugePageSize() ) -var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist") +var errSubsystemDoesNotExist = fmt.Errorf("cgroup: subsystem does not exist") type subsystemSet []subsystem @@ -64,9 +63,10 @@ type subsystem interface { } type Manager struct { - mu sync.Mutex - Cgroups *configs.Cgroup - Paths map[string]string + mu sync.Mutex + Cgroups *configs.Cgroup + Rootless bool // ignore permission-related errors + Paths map[string]string } // The absolute path to the root of the cgroup hierarchies. @@ -102,10 +102,39 @@ type cgroupData struct { pid int } +// isIgnorableError returns whether err is a permission error (in the loose +// sense of the word). This includes EROFS (which for an unprivileged user is +// basically a permission error) and EACCES (for similar reasons) as well as +// the normal EPERM. +func isIgnorableError(rootless bool, err error) bool { + // We do not ignore errors if we are root. + if !rootless { + return false + } + // Is it an ordinary EPERM? + if os.IsPermission(errors.Cause(err)) { + return true + } + + // Try to handle other errnos. + var errno error + switch err := errors.Cause(err).(type) { + case *os.PathError: + errno = err.Err + case *os.LinkError: + errno = err.Err + case *os.SyscallError: + errno = err.Err + } + return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES +} + func (m *Manager) Apply(pid int) (err error) { if m.Cgroups == nil { return nil } + m.mu.Lock() + defer m.mu.Unlock() var c = m.Cgroups @@ -114,8 +143,8 @@ func (m *Manager) Apply(pid int) (err error) { return err } + m.Paths = make(map[string]string) if c.Paths != nil { - paths := make(map[string]string) for name, path := range c.Paths { _, err := d.path(name) if err != nil { @@ -124,37 +153,44 @@ func (m *Manager) Apply(pid int) (err error) { } return err } - paths[name] = path + m.Paths[name] = path } - m.Paths = paths return cgroups.EnterPid(m.Paths, pid) } - m.mu.Lock() - defer m.mu.Unlock() - paths := make(map[string]string) for _, sys := range subsystems { - if err := sys.Apply(d); err != nil { - return err - } // TODO: Apply should, ideally, be reentrant or be broken up into a separate // create and join phase so that the cgroup hierarchy for a container can be // created then join consists of writing the process pids to cgroup.procs p, err := d.path(sys.Name()) if err != nil { - if cgroups.IsNotFound(err) { + // The non-presence of the devices subsystem is + // considered fatal for security reasons. + if cgroups.IsNotFound(err) && sys.Name() != "devices" { + continue + } + return err + } + m.Paths[sys.Name()] = p + + if err := sys.Apply(d); err != nil { + // In the case of rootless (including euid=0 in userns), where an explicit cgroup path hasn't + // been set, we don't bail on error in case of permission problems. + // Cases where limits have been set (and we couldn't create our own + // cgroup) are handled by Set. + if isIgnorableError(m.Rootless, err) && m.Cgroups.Path == "" { + delete(m.Paths, sys.Name()) continue } return err } - paths[sys.Name()] = p + } - m.Paths = paths return nil } func (m *Manager) Destroy() error { - if m.Cgroups.Paths != nil { + if m.Cgroups == nil || m.Cgroups.Paths != nil { return nil } m.mu.Lock() @@ -190,19 +226,27 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { } func (m *Manager) Set(container *configs.Config) error { - for _, sys := range subsystems { - // Generate fake cgroup data. - d, err := getCgroupData(container.Cgroups, -1) - if err != nil { - return err - } - // Get the path, but don't error out if the cgroup wasn't found. - path, err := d.path(sys.Name()) - if err != nil && !cgroups.IsNotFound(err) { - return err - } + // If Paths are set, then we are just joining cgroups paths + // and there is no need to set any values. + if m.Cgroups.Paths != nil { + return nil + } + paths := m.GetPaths() + for _, sys := range subsystems { + path := paths[sys.Name()] if err := sys.Set(path, container.Cgroups); err != nil { + if m.Rootless && sys.Name() == "devices" { + continue + } + // When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work. + // However, errors from other subsystems are not ignored. + // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error" + if path == "" { + // We never created a path for this cgroup, so we cannot set + // limits for it (though we have already tried at this point). + return fmt.Errorf("cannot set %s limit: container could not join or create cgroup", sys.Name()) + } return err } } @@ -218,14 +262,8 @@ func (m *Manager) Set(container *configs.Config) error { // Freeze toggles the container's freezer cgroup depending on the state // provided func (m *Manager) Freeze(state configs.FreezerState) error { - d, err := getCgroupData(m.Cgroups, 0) - if err != nil { - return err - } - dir, err := d.path("freezer") - if err != nil { - return err - } + paths := m.GetPaths() + dir := paths["freezer"] prevState := m.Cgroups.Resources.Freezer m.Cgroups.Resources.Freezer = state freezer, err := subsystems.Get("freezer") @@ -241,28 +279,13 @@ func (m *Manager) Freeze(state configs.FreezerState) error { } func (m *Manager) GetPids() ([]int, error) { - dir, err := getCgroupPath(m.Cgroups) - if err != nil { - return nil, err - } - return cgroups.GetPids(dir) + paths := m.GetPaths() + return cgroups.GetPids(paths["devices"]) } func (m *Manager) GetAllPids() ([]int, error) { - dir, err := getCgroupPath(m.Cgroups) - if err != nil { - return nil, err - } - return cgroups.GetAllPids(dir) -} - -func getCgroupPath(c *configs.Cgroup) (string, error) { - d, err := getCgroupData(c, 0) - if err != nil { - return "", err - } - - return d.path("devices") + paths := m.GetPaths() + return cgroups.GetAllPids(paths["devices"]) } func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { @@ -293,25 +316,8 @@ func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { }, nil } -func (raw *cgroupData) parentPath(subsystem, mountpoint, root string) (string, error) { - // Use GetThisCgroupDir instead of GetInitCgroupDir, because the creating - // process could in container and shared pid namespace with host, and - // /proc/1/cgroup could point to whole other world of cgroups. - initPath, err := cgroups.GetThisCgroupDir(subsystem) - if err != nil { - return "", err - } - // This is needed for nested containers, because in /proc/self/cgroup we - // see pathes from host, which don't exist in container. - relDir, err := filepath.Rel(root, initPath) - if err != nil { - return "", err - } - return filepath.Join(mountpoint, relDir), nil -} - func (raw *cgroupData) path(subsystem string) (string, error) { - mnt, root, err := cgroups.FindCgroupMountpointAndRoot(subsystem) + mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem) // If we didn't mount the subsystem, there is no point we make the path. if err != nil { return "", err @@ -319,11 +325,14 @@ func (raw *cgroupData) path(subsystem string) (string, error) { // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. if filepath.IsAbs(raw.innerPath) { - // Sometimes subsystems can be mounted togethger as 'cpu,cpuacct'. + // Sometimes subsystems can be mounted together as 'cpu,cpuacct'. return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil } - parentPath, err := raw.parentPath(subsystem, mnt, root) + // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating + // process could in container and shared pid namespace with host, and + // /proc/1/cgroup could point to whole other world of cgroups. + parentPath, err := cgroups.GetOwnCgroupPath(subsystem) if err != nil { return "", err } @@ -339,7 +348,7 @@ func (raw *cgroupData) join(subsystem string) (string, error) { if err := os.MkdirAll(path, 0755); err != nil { return "", err } - if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil { + if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil { return "", err } return path, nil @@ -349,9 +358,12 @@ func writeFile(dir, file, data string) error { // Normally dir should not be empty, one case is that cgroup subsystem // is not mounted, we will get empty dir, and we want it fail here. if dir == "" { - return fmt.Errorf("no such directory for %s.", file) + return fmt.Errorf("no such directory for %s", file) + } + if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", data, file, err) } - return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) + return nil } func readFile(dir, file string) (string, error) { @@ -369,8 +381,8 @@ func removePath(p string, err error) error { return nil } -func CheckCpushares(path string, c int64) error { - var cpuShares int64 +func CheckCpushares(path string, c uint64) error { + var cpuShares uint64 if c == 0 { return nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go index a4ef28a60f87e459d212108234674676e113d474..e240a8313a2091a1e40983514c21a5016809ecbf 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go @@ -22,41 +22,64 @@ func (s *CpuGroup) Name() string { func (s *CpuGroup) Apply(d *cgroupData) error { // We always want to join the cpu group, to allow fair cpu scheduling // on a container basis - _, err := d.join("cpu") + path, err := d.path("cpu") if err != nil && !cgroups.IsNotFound(err) { return err } - return nil + return s.ApplyDir(path, d.config, d.pid) } -func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error { - if cgroup.Resources.CpuShares != 0 { - if err := writeFile(path, "cpu.shares", strconv.FormatInt(cgroup.Resources.CpuShares, 10)); err != nil { +func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error { + // This might happen if we have no cpu cgroup mounted. + // Just do nothing and don't fail. + if path == "" { + return nil + } + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + // We should set the real-Time group scheduling settings before moving + // in the process because if the process is already in SCHED_RR mode + // and no RT bandwidth is set, adding it will fail. + if err := s.SetRtSched(path, cgroup); err != nil { + return err + } + // because we are not using d.join we need to place the pid into the procs file + // unlike the other subsystems + return cgroups.WriteCgroupProc(path, pid) +} + +func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.CpuRtPeriod != 0 { + if err := writeFile(path, "cpu.rt_period_us", strconv.FormatUint(cgroup.Resources.CpuRtPeriod, 10)); err != nil { return err } } - if cgroup.Resources.CpuPeriod != 0 { - if err := writeFile(path, "cpu.cfs_period_us", strconv.FormatInt(cgroup.Resources.CpuPeriod, 10)); err != nil { + if cgroup.Resources.CpuRtRuntime != 0 { + if err := writeFile(path, "cpu.rt_runtime_us", strconv.FormatInt(cgroup.Resources.CpuRtRuntime, 10)); err != nil { return err } } - if cgroup.Resources.CpuQuota != 0 { - if err := writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(cgroup.Resources.CpuQuota, 10)); err != nil { + return nil +} + +func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.Resources.CpuShares != 0 { + if err := writeFile(path, "cpu.shares", strconv.FormatUint(cgroup.Resources.CpuShares, 10)); err != nil { return err } } - if cgroup.Resources.CpuRtPeriod != 0 { - if err := writeFile(path, "cpu.rt_period_us", strconv.FormatInt(cgroup.Resources.CpuRtPeriod, 10)); err != nil { + if cgroup.Resources.CpuPeriod != 0 { + if err := writeFile(path, "cpu.cfs_period_us", strconv.FormatUint(cgroup.Resources.CpuPeriod, 10)); err != nil { return err } } - if cgroup.Resources.CpuRtRuntime != 0 { - if err := writeFile(path, "cpu.rt_runtime_us", strconv.FormatInt(cgroup.Resources.CpuRtRuntime, 10)); err != nil { + if cgroup.Resources.CpuQuota != 0 { + if err := writeFile(path, "cpu.cfs_quota_us", strconv.FormatInt(cgroup.Resources.CpuQuota, 10)); err != nil { return err } } - - return nil + return s.SetRtSched(path, cgroup) } func (s *CpuGroup) Remove(d *cgroupData) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go index 554fd5e85df53bd6623c6399bcd0558057f2eb5c..6369c91ad65433c0da245b5af106b27a0a350e57 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu_test.go @@ -106,13 +106,13 @@ func TestCpuStats(t *testing.T) { defer helper.cleanup() const ( - kNrPeriods = 2000 - kNrThrottled = 200 - kThrottledTime = uint64(18446744073709551615) + nrPeriods = 2000 + nrThrottled = 200 + throttledTime = uint64(18446744073709551615) ) cpuStatContent := fmt.Sprintf("nr_periods %d\n nr_throttled %d\n throttled_time %d\n", - kNrPeriods, kNrThrottled, kThrottledTime) + nrPeriods, nrThrottled, throttledTime) helper.writeFileContents(map[string]string{ "cpu.stat": cpuStatContent, }) @@ -125,9 +125,9 @@ func TestCpuStats(t *testing.T) { } expectedStats := cgroups.ThrottlingData{ - Periods: kNrPeriods, - ThrottledPeriods: kNrThrottled, - ThrottledTime: kThrottledTime} + Periods: nrPeriods, + ThrottledPeriods: nrThrottled, + ThrottledTime: throttledTime} expectThrottlingDataEquals(t, expectedStats, actualStats.CpuStats.ThrottlingData) } @@ -161,3 +161,49 @@ func TestInvalidCpuStat(t *testing.T) { t.Fatal("Expected failed stat parsing.") } } + +func TestCpuSetRtSchedAtApply(t *testing.T) { + helper := NewCgroupTestUtil("cpu", t) + defer helper.cleanup() + + const ( + rtRuntimeBefore = 0 + rtRuntimeAfter = 5000 + rtPeriodBefore = 0 + rtPeriodAfter = 7000 + ) + + helper.writeFileContents(map[string]string{ + "cpu.rt_runtime_us": strconv.Itoa(rtRuntimeBefore), + "cpu.rt_period_us": strconv.Itoa(rtPeriodBefore), + }) + + helper.CgroupData.config.Resources.CpuRtRuntime = rtRuntimeAfter + helper.CgroupData.config.Resources.CpuRtPeriod = rtPeriodAfter + cpu := &CpuGroup{} + if err := cpu.ApplyDir(helper.CgroupPath, helper.CgroupData.config, 1234); err != nil { + t.Fatal(err) + } + + rtRuntime, err := getCgroupParamUint(helper.CgroupPath, "cpu.rt_runtime_us") + if err != nil { + t.Fatalf("Failed to parse cpu.rt_runtime_us - %s", err) + } + if rtRuntime != rtRuntimeAfter { + t.Fatal("Got the wrong value, set cpu.rt_runtime_us failed.") + } + rtPeriod, err := getCgroupParamUint(helper.CgroupPath, "cpu.rt_period_us") + if err != nil { + t.Fatalf("Failed to parse cpu.rt_period_us - %s", err) + } + if rtPeriod != rtPeriodAfter { + t.Fatal("Got the wrong value, set cpu.rt_period_us failed.") + } + pid, err := getCgroupParamUint(helper.CgroupPath, "cgroup.procs") + if err != nil { + t.Fatalf("Failed to parse cgroup.procs - %s", err) + } + if pid != 1234 { + t.Fatal("Got the wrong value, set cgroup.procs failed.") + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go index cbe62bd983aad33ae6478cc1469a313c30428dc0..5a1d152ea1dbd70eb2010020efac4f0bb689fac0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go @@ -8,7 +8,6 @@ import ( "io/ioutil" "os" "path/filepath" - "strconv" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" @@ -58,20 +57,34 @@ func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) erro if dir == "" { return nil } - root, err := getCgroupRoot() + mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo") if err != nil { return err } - if err := s.ensureParent(dir, root); err != nil { + root := filepath.Dir(cgroups.GetClosestMountpointAncestor(dir, string(mountInfo))) + // 'ensureParent' start with parent because we don't want to + // explicitly inherit from parent, it could conflict with + // 'cpuset.cpu_exclusive'. + if err := s.ensureParent(filepath.Dir(dir), root); err != nil { return err } - // because we are not using d.join we need to place the pid into the procs file - // unlike the other subsystems - if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil { + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + // We didn't inherit cpuset configs from parent, but we have + // to ensure cpuset configs are set before moving task into the + // cgroup. + // The logic is, if user specified cpuset configs, use these + // specified configs, otherwise, inherit from parent. This makes + // cpuset configs work correctly with 'cpuset.cpu_exclusive', and + // keep backward compatibility. + if err := s.ensureCpusAndMems(dir, cgroup); err != nil { return err } - return nil + // because we are not using d.join we need to place the pid into the procs file + // unlike the other subsystems + return cgroups.WriteCgroupProc(dir, pid) } func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) { @@ -137,3 +150,10 @@ func (s *CpusetGroup) copyIfNeeded(current, parent string) error { func (s *CpusetGroup) isEmpty(b []byte) bool { return len(bytes.Trim(b, "\n")) == 0 } + +func (s *CpusetGroup) ensureCpusAndMems(path string, cgroup *configs.Cgroup) error { + if err := s.Set(path, cgroup); err != nil { + return err + } + return s.copyIfNeeded(path, filepath.Dir(path)) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go index 5f783310947df5f0ec61bf1b07cd98b65e4326a6..0ac5b4ed70037dc52f6a87f91fb90abd4838ab7c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go @@ -43,21 +43,23 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { } return nil } - if !cgroup.Resources.AllowAllDevices { - if err := writeFile(path, "devices.deny", "a"); err != nil { - return err - } - - for _, dev := range cgroup.Resources.AllowedDevices { - if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil { + if cgroup.Resources.AllowAllDevices != nil { + if *cgroup.Resources.AllowAllDevices == false { + if err := writeFile(path, "devices.deny", "a"); err != nil { return err } + + for _, dev := range cgroup.Resources.AllowedDevices { + if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil { + return err + } + } + return nil } - return nil - } - if err := writeFile(path, "devices.allow", "a"); err != nil { - return err + if err := writeFile(path, "devices.allow", "a"); err != nil { + return err + } } for _, dev := range cgroup.Resources.DeniedDevices { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go index ee44084eec40079fa7e085e10a99b9c32dd0e5b1..fc635b990f56a828654fb3c9b66d414c1578b76a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices_test.go @@ -40,8 +40,8 @@ func TestDevicesSetAllow(t *testing.T) { helper.writeFileContents(map[string]string{ "devices.deny": "a", }) - - helper.CgroupData.config.Resources.AllowAllDevices = false + allowAllDevices := false + helper.CgroupData.config.Resources.AllowAllDevices = &allowAllDevices helper.CgroupData.config.Resources.AllowedDevices = allowedDevices devices := &DevicesGroup{} if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { @@ -56,6 +56,19 @@ func TestDevicesSetAllow(t *testing.T) { if value != allowedList { t.Fatal("Got the wrong value, set devices.allow failed.") } + + // When AllowAllDevices is nil, devices.allow file should not be modified. + helper.CgroupData.config.Resources.AllowAllDevices = nil + if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { + t.Fatal(err) + } + value, err = getCgroupParamString(helper.CgroupPath, "devices.allow") + if err != nil { + t.Fatalf("Failed to parse devices.allow - %s", err) + } + if value != allowedList { + t.Fatal("devices policy shouldn't have changed on AllowedAllDevices=nil.") + } } func TestDevicesSetDeny(t *testing.T) { @@ -66,7 +79,8 @@ func TestDevicesSetDeny(t *testing.T) { "devices.allow": "a", }) - helper.CgroupData.config.Resources.AllowAllDevices = true + allowAllDevices := true + helper.CgroupData.config.Resources.AllowAllDevices = &allowAllDevices helper.CgroupData.config.Resources.DeniedDevices = deniedDevices devices := &DevicesGroup{} if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go index e70dfe3b950f7780f9b3f7057ff0995b664057d3..4b19f8a970d731a409603b4a98adef8f100b3b3d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go @@ -29,11 +29,15 @@ func (s *FreezerGroup) Apply(d *cgroupData) error { func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error { switch cgroup.Resources.Freezer { case configs.Frozen, configs.Thawed: - if err := writeFile(path, "freezer.state", string(cgroup.Resources.Freezer)); err != nil { - return err - } - for { + // In case this loop does not exit because it doesn't get the expected + // state, let's write again this state, hoping it's going to be properly + // set this time. Otherwise, this loop could run infinitely, waiting for + // a state change that would never happen. + if err := writeFile(path, "freezer.state", string(cgroup.Resources.Freezer)); err != nil { + return err + } + state, err := readFile(path, "freezer.state") if err != nil { return err @@ -41,6 +45,7 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error { if strings.TrimSpace(state) == string(cgroup.Resources.Freezer) { break } + time.Sleep(1 * time.Millisecond) } case configs.Undefined: diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go new file mode 100644 index 0000000000000000000000000000000000000000..69b5a1946c72e96c49bf09eda68af0590cead0ed --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go @@ -0,0 +1,62 @@ +// +build linux,!nokmem + +package fs + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "syscall" // for Errno type only + + "github.com/opencontainers/runc/libcontainer/cgroups" + "golang.org/x/sys/unix" +) + +const cgroupKernelMemoryLimit = "memory.kmem.limit_in_bytes" + +func EnableKernelMemoryAccounting(path string) error { + // Ensure that kernel memory is available in this kernel build. If it + // isn't, we just ignore it because EnableKernelMemoryAccounting is + // automatically called for all memory limits. + if !cgroups.PathExists(filepath.Join(path, cgroupKernelMemoryLimit)) { + return nil + } + // We have to limit the kernel memory here as it won't be accounted at all + // until a limit is set on the cgroup and limit cannot be set once the + // cgroup has children, or if there are already tasks in the cgroup. + for _, i := range []int64{1, -1} { + if err := setKernelMemory(path, i); err != nil { + return err + } + } + return nil +} + +func setKernelMemory(path string, kernelMemoryLimit int64) error { + if path == "" { + return fmt.Errorf("no such directory for %s", cgroupKernelMemoryLimit) + } + if !cgroups.PathExists(filepath.Join(path, cgroupKernelMemoryLimit)) { + // We have specifically been asked to set a kmem limit. If the kernel + // doesn't support it we *must* error out. + return errors.New("kernel memory accounting not supported by this kernel") + } + if err := ioutil.WriteFile(filepath.Join(path, cgroupKernelMemoryLimit), []byte(strconv.FormatInt(kernelMemoryLimit, 10)), 0700); err != nil { + // Check if the error number returned by the syscall is "EBUSY" + // The EBUSY signal is returned on attempts to write to the + // memory.kmem.limit_in_bytes file if the cgroup has children or + // once tasks have been attached to the cgroup + if pathErr, ok := err.(*os.PathError); ok { + if errNo, ok := pathErr.Err.(syscall.Errno); ok { + if errNo == unix.EBUSY { + return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit) + } + } + } + return fmt.Errorf("failed to write %v to %v: %v", kernelMemoryLimit, cgroupKernelMemoryLimit, err) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go new file mode 100644 index 0000000000000000000000000000000000000000..ac290fd7a02a7298b6c15aa07378e33d0343c8d4 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem_disabled.go @@ -0,0 +1,15 @@ +// +build linux,nokmem + +package fs + +import ( + "errors" +) + +func EnableKernelMemoryAccounting(path string) error { + return nil +} + +func setKernelMemory(path string, kernelMemoryLimit int64) error { + return errors.New("kernel memory accounting disabled in this runc build") +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index e3fd327e91fc60e847980bb1abfd634c79284918..d5310d569f2689d442131a6d6c6b3fa1d0df21c5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -14,6 +14,11 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" ) +const ( + cgroupMemorySwapLimit = "memory.memsw.limit_in_bytes" + cgroupMemoryLimit = "memory.limit_in_bytes" +) + type MemoryGroup struct { } @@ -25,20 +30,23 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) { path, err := d.path("memory") if err != nil && !cgroups.IsNotFound(err) { return err + } else if path == "" { + return nil } if memoryAssigned(d.config) { - if path != "" { + if _, err := os.Stat(path); os.IsNotExist(err) { if err := os.MkdirAll(path, 0755); err != nil { return err } - } - // We have to set kernel memory here, as we can't change it once - // processes have been attached. - if err := s.SetKernelMemory(path, d.config); err != nil { - return err + // Only enable kernel memory accouting when this cgroup + // is created by libcontainer, otherwise we might get + // error when people use `cgroupsPath` to join an existed + // cgroup whose kernel memory is not initialized. + if err := EnableKernelMemoryAccounting(path); err != nil { + return err + } } } - defer func() { if err != nil { os.RemoveAll(path) @@ -54,30 +62,77 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) { return nil } -func (s *MemoryGroup) SetKernelMemory(path string, cgroup *configs.Cgroup) error { - // This has to be done separately because it has special constraints (it - // can't be done after there are processes attached to the cgroup). - if cgroup.Resources.KernelMemory > 0 { - if err := writeFile(path, "memory.kmem.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemory, 10)); err != nil { +func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error { + // If the memory update is set to -1 we should also + // set swap to -1, it means unlimited memory. + if cgroup.Resources.Memory == -1 { + // Only set swap if it's enabled in kernel + if cgroups.PathExists(filepath.Join(path, cgroupMemorySwapLimit)) { + cgroup.Resources.MemorySwap = -1 + } + } + + // When memory and swap memory are both set, we need to handle the cases + // for updating container. + if cgroup.Resources.Memory != 0 && cgroup.Resources.MemorySwap != 0 { + memoryUsage, err := getMemoryData(path, "") + if err != nil { return err } + + // When update memory limit, we should adapt the write sequence + // for memory and swap memory, so it won't fail because the new + // value and the old value don't fit kernel's validation. + if cgroup.Resources.MemorySwap == -1 || memoryUsage.Limit < uint64(cgroup.Resources.MemorySwap) { + if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil { + return err + } + if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil { + return err + } + } else { + if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil { + return err + } + if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil { + return err + } + } + } else { + if cgroup.Resources.Memory != 0 { + if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil { + return err + } + } + if cgroup.Resources.MemorySwap != 0 { + if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil { + return err + } + } } + return nil } func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error { - if cgroup.Resources.Memory != 0 { - if err := writeFile(path, "memory.limit_in_bytes", strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil { + if err := setMemoryAndSwap(path, cgroup); err != nil { + return err + } + + if cgroup.Resources.KernelMemory != 0 { + if err := setKernelMemory(path, cgroup.Resources.KernelMemory); err != nil { return err } } + if cgroup.Resources.MemoryReservation != 0 { if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil { return err } } - if cgroup.Resources.MemorySwap > 0 { - if err := writeFile(path, "memory.memsw.limit_in_bytes", strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil { + + if cgroup.Resources.KernelMemoryTCP != 0 { + if err := writeFile(path, "memory.kmem.tcp.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemoryTCP, 10)); err != nil { return err } } @@ -88,12 +143,12 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error { } if cgroup.Resources.MemorySwappiness == nil || int64(*cgroup.Resources.MemorySwappiness) == -1 { return nil - } else if int64(*cgroup.Resources.MemorySwappiness) >= 0 && int64(*cgroup.Resources.MemorySwappiness) <= 100 { - if err := writeFile(path, "memory.swappiness", strconv.FormatInt(*cgroup.Resources.MemorySwappiness, 10)); err != nil { + } else if *cgroup.Resources.MemorySwappiness <= 100 { + if err := writeFile(path, "memory.swappiness", strconv.FormatUint(*cgroup.Resources.MemorySwappiness, 10)); err != nil { return err } } else { - return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", int64(*cgroup.Resources.MemorySwappiness)) + return fmt.Errorf("invalid value:%d. valid memory swappiness range is 0-100", *cgroup.Resources.MemorySwappiness) } return nil @@ -139,7 +194,20 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { return err } stats.MemoryStats.KernelUsage = kernelUsage + kernelTCPUsage, err := getMemoryData(path, "kmem.tcp") + if err != nil { + return err + } + stats.MemoryStats.KernelTCPUsage = kernelTCPUsage + useHierarchy := strings.Join([]string{"memory", "use_hierarchy"}, ".") + value, err := getCgroupParamUint(path, useHierarchy) + if err != nil { + return err + } + if value == 1 { + stats.MemoryStats.UseHierarchy = true + } return nil } @@ -148,8 +216,9 @@ func memoryAssigned(cgroup *configs.Cgroup) bool { cgroup.Resources.MemoryReservation != 0 || cgroup.Resources.MemorySwap > 0 || cgroup.Resources.KernelMemory > 0 || + cgroup.Resources.KernelMemoryTCP > 0 || cgroup.Resources.OomKillDisable || - (cgroup.Resources.MemorySwappiness != nil && *cgroup.Resources.MemorySwappiness != -1) + (cgroup.Resources.MemorySwappiness != nil && int64(*cgroup.Resources.MemorySwappiness) != -1) } func getMemoryData(path, name string) (cgroups.MemoryData, error) { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go index 8321ce97c74f2c3e732f7558957f84e1c495517b..4e0ae7b26e53d74ebcadd88902deceb738997e24 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory_test.go @@ -12,10 +12,11 @@ import ( const ( memoryStatContents = `cache 512 rss 1024` - memoryUsageContents = "2048\n" - memoryMaxUsageContents = "4096\n" - memoryFailcnt = "100\n" - memoryLimitContents = "8192\n" + memoryUsageContents = "2048\n" + memoryMaxUsageContents = "4096\n" + memoryFailcnt = "100\n" + memoryLimitContents = "8192\n" + memoryUseHierarchyContents = "1\n" ) func TestMemorySetMemory(t *testing.T) { @@ -86,6 +87,94 @@ func TestMemorySetMemoryswap(t *testing.T) { } } +func TestMemorySetMemoryLargerThanSwap(t *testing.T) { + helper := NewCgroupTestUtil("memory", t) + defer helper.cleanup() + + const ( + memoryBefore = 314572800 // 300M + memoryswapBefore = 524288000 // 500M + memoryAfter = 629145600 // 600M + memoryswapAfter = 838860800 // 800M + ) + + helper.writeFileContents(map[string]string{ + "memory.limit_in_bytes": strconv.Itoa(memoryBefore), + "memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore), + // Set will call getMemoryData when memory and swap memory are + // both set, fake these fields so we don't get error. + "memory.usage_in_bytes": "0", + "memory.max_usage_in_bytes": "0", + "memory.failcnt": "0", + }) + + helper.CgroupData.config.Resources.Memory = memoryAfter + helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter + memory := &MemoryGroup{} + if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { + t.Fatal(err) + } + + value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes") + if err != nil { + t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err) + } + if value != memoryAfter { + t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.") + } + value, err = getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes") + if err != nil { + t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err) + } + if value != memoryswapAfter { + t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.") + } +} + +func TestMemorySetSwapSmallerThanMemory(t *testing.T) { + helper := NewCgroupTestUtil("memory", t) + defer helper.cleanup() + + const ( + memoryBefore = 629145600 // 600M + memoryswapBefore = 838860800 // 800M + memoryAfter = 314572800 // 300M + memoryswapAfter = 524288000 // 500M + ) + + helper.writeFileContents(map[string]string{ + "memory.limit_in_bytes": strconv.Itoa(memoryBefore), + "memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore), + // Set will call getMemoryData when memory and swap memory are + // both set, fake these fields so we don't get error. + "memory.usage_in_bytes": "0", + "memory.max_usage_in_bytes": "0", + "memory.failcnt": "0", + }) + + helper.CgroupData.config.Resources.Memory = memoryAfter + helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter + memory := &MemoryGroup{} + if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { + t.Fatal(err) + } + + value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes") + if err != nil { + t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err) + } + if value != memoryAfter { + t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.") + } + value, err = getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes") + if err != nil { + t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err) + } + if value != memoryswapAfter { + t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.") + } +} + func TestMemorySetKernelMemory(t *testing.T) { helper := NewCgroupTestUtil("memory", t) defer helper.cleanup() @@ -101,7 +190,7 @@ func TestMemorySetKernelMemory(t *testing.T) { helper.CgroupData.config.Resources.KernelMemory = kernelMemoryAfter memory := &MemoryGroup{} - if err := memory.SetKernelMemory(helper.CgroupPath, helper.CgroupData.config); err != nil { + if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { t.Fatal(err) } @@ -114,12 +203,40 @@ func TestMemorySetKernelMemory(t *testing.T) { } } +func TestMemorySetKernelMemoryTCP(t *testing.T) { + helper := NewCgroupTestUtil("memory", t) + defer helper.cleanup() + + const ( + kernelMemoryTCPBefore = 314572800 // 300M + kernelMemoryTCPAfter = 524288000 // 500M + ) + + helper.writeFileContents(map[string]string{ + "memory.kmem.tcp.limit_in_bytes": strconv.Itoa(kernelMemoryTCPBefore), + }) + + helper.CgroupData.config.Resources.KernelMemoryTCP = kernelMemoryTCPAfter + memory := &MemoryGroup{} + if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { + t.Fatal(err) + } + + value, err := getCgroupParamUint(helper.CgroupPath, "memory.kmem.tcp.limit_in_bytes") + if err != nil { + t.Fatalf("Failed to parse memory.kmem.tcp.limit_in_bytes - %s", err) + } + if value != kernelMemoryTCPAfter { + t.Fatal("Got the wrong value, set memory.kmem.tcp.limit_in_bytes failed.") + } +} + func TestMemorySetMemorySwappinessDefault(t *testing.T) { helper := NewCgroupTestUtil("memory", t) defer helper.cleanup() swappinessBefore := 60 //default is 60 - swappinessAfter := int64(0) + swappinessAfter := uint64(0) helper.writeFileContents(map[string]string{ "memory.swappiness": strconv.Itoa(swappinessBefore), @@ -135,7 +252,7 @@ func TestMemorySetMemorySwappinessDefault(t *testing.T) { if err != nil { t.Fatalf("Failed to parse memory.swappiness - %s", err) } - if int64(value) != swappinessAfter { + if value != swappinessAfter { t.Fatalf("Got the wrong value (%d), set memory.swappiness = %d failed.", value, swappinessAfter) } } @@ -157,6 +274,7 @@ func TestMemoryStats(t *testing.T) { "memory.kmem.max_usage_in_bytes": memoryMaxUsageContents, "memory.kmem.failcnt": memoryFailcnt, "memory.kmem.limit_in_bytes": memoryLimitContents, + "memory.use_hierarchy": memoryUseHierarchyContents, }) memory := &MemoryGroup{} @@ -165,7 +283,7 @@ func TestMemoryStats(t *testing.T) { if err != nil { t.Fatal(err) } - expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, Stats: map[string]uint64{"cache": 512, "rss": 1024}} + expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, Stats: map[string]uint64{"cache": 512, "rss": 1024}, UseHierarchy: true} expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats) } @@ -314,11 +432,11 @@ func TestMemorySetOomControl(t *testing.T) { defer helper.cleanup() const ( - oom_kill_disable = 1 // disable oom killer, default is 0 + oomKillDisable = 1 // disable oom killer, default is 0 ) helper.writeFileContents(map[string]string{ - "memory.oom_control": strconv.Itoa(oom_kill_disable), + "memory.oom_control": strconv.Itoa(oomKillDisable), }) memory := &MemoryGroup{} @@ -331,7 +449,7 @@ func TestMemorySetOomControl(t *testing.T) { t.Fatalf("Failed to parse memory.oom_control - %s", err) } - if value != oom_kill_disable { + if value != oomKillDisable { t.Fatalf("Got the wrong value, set memory.oom_control failed.") } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go index 8a4054ba8776c00b013b02371d691e86b764a9ba..8e74b645eac78129bfa39a4d32b889bd12abfca6 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go @@ -3,6 +3,8 @@ package fs import ( + "strconv" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" ) @@ -23,8 +25,8 @@ func (s *NetClsGroup) Apply(d *cgroupData) error { } func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error { - if cgroup.Resources.NetClsClassid != "" { - if err := writeFile(path, "net_cls.classid", cgroup.Resources.NetClsClassid); err != nil { + if cgroup.Resources.NetClsClassid != 0 { + if err := writeFile(path, "net_cls.classid", strconv.FormatUint(uint64(cgroup.Resources.NetClsClassid), 10)); err != nil { return err } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go index 974bd9d887754c35c5203e094f1491f8f64f58db..c00e8a8d6f4d0872b95f2856838ae8748207cf7f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls_test.go @@ -3,12 +3,13 @@ package fs import ( + "strconv" "testing" ) const ( - classidBefore = "0x100002" - classidAfter = "0x100001" + classidBefore = 0x100002 + classidAfter = 0x100001 ) func TestNetClsSetClassid(t *testing.T) { @@ -16,7 +17,7 @@ func TestNetClsSetClassid(t *testing.T) { defer helper.cleanup() helper.writeFileContents(map[string]string{ - "net_cls.classid": classidBefore, + "net_cls.classid": strconv.FormatUint(classidBefore, 10), }) helper.CgroupData.config.Resources.NetClsClassid = classidAfter @@ -28,7 +29,7 @@ func TestNetClsSetClassid(t *testing.T) { // As we are in mock environment, we can't get correct value of classid from // net_cls.classid. // So. we just judge if we successfully write classid into file - value, err := getCgroupParamString(helper.CgroupPath, "net_cls.classid") + value, err := getCgroupParamUint(helper.CgroupPath, "net_cls.classid") if err != nil { t.Fatalf("Failed to parse net_cls.classid - %s", err) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go index 96cbb896cb19827fd65398e7ee4b958658508685..f1e37205518b0759535d10103ecb4caee8512c2f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go @@ -4,6 +4,7 @@ package fs import ( "fmt" + "path/filepath" "strconv" "github.com/opencontainers/runc/libcontainer/cgroups" @@ -47,11 +48,26 @@ func (s *PidsGroup) Remove(d *cgroupData) error { } func (s *PidsGroup) GetStats(path string, stats *cgroups.Stats) error { - value, err := getCgroupParamUint(path, "pids.current") + current, err := getCgroupParamUint(path, "pids.current") if err != nil { return fmt.Errorf("failed to parse pids.current - %s", err) } - stats.PidsStats.Current = value + maxString, err := getCgroupParamString(path, "pids.max") + if err != nil { + return fmt.Errorf("failed to parse pids.max - %s", err) + } + + // Default if pids.max == "max" is 0 -- which represents "no limit". + var max uint64 + if maxString != "max" { + max, err = parseUint(maxString, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse pids.max - unable to parse %q as a uint from Cgroup file %q", maxString, filepath.Join(path, "pids.max")) + } + } + + stats.PidsStats.Current = current + stats.PidsStats.Limit = max return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go index 06b11927aa833e8ad41f9ddd4b44621809c5f8c9..10671247ba38e4c5d8ec05fb9e713f55d5ea7679 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids_test.go @@ -80,4 +80,32 @@ func TestPidsStats(t *testing.T) { if stats.PidsStats.Current != 1337 { t.Fatalf("Expected %d, got %d for pids.current", 1337, stats.PidsStats.Current) } + + if stats.PidsStats.Limit != maxLimited { + t.Fatalf("Expected %d, got %d for pids.max", maxLimited, stats.PidsStats.Limit) + } +} + +func TestPidsStatsUnlimited(t *testing.T) { + helper := NewCgroupTestUtil("pids", t) + defer helper.cleanup() + + helper.writeFileContents(map[string]string{ + "pids.current": strconv.Itoa(4096), + "pids.max": "max", + }) + + pids := &PidsGroup{} + stats := *cgroups.NewStats() + if err := pids.GetStats(helper.CgroupPath, &stats); err != nil { + t.Fatal(err) + } + + if stats.PidsStats.Current != 4096 { + t.Fatalf("Expected %d, got %d for pids.current", 4096, stats.PidsStats.Current) + } + + if stats.PidsStats.Limit != 0 { + t.Fatalf("Expected %d, got %d for pids.max", 0, stats.PidsStats.Limit) + } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go index d0ab047418f4a630a0936edb2c00a01bcdd2cba5..c5a8d185824b8240ae8e988a0eaf7f6a94268d6d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/stats_util_test.go @@ -6,8 +6,9 @@ import ( "fmt" "testing" - "github.com/sirupsen/logrus" "github.com/opencontainers/runc/libcontainer/cgroups" + + "github.com/sirupsen/logrus" ) func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error { @@ -84,6 +85,11 @@ func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats) expectMemoryDataEquals(t, expected.SwapUsage, actual.SwapUsage) expectMemoryDataEquals(t, expected.KernelUsage, actual.KernelUsage) + if expected.UseHierarchy != actual.UseHierarchy { + logrus.Printf("Expected memory use hierarchy %v, but found %v\n", expected.UseHierarchy, actual.UseHierarchy) + t.Fail() + } + for key, expValue := range expected.Stats { actValue, ok := actual.Stats[key] if !ok { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go index 852b18391d0bcd53c31e8b3866c087160cca3c53..5ff0a1615048cba54b107c2dcabd3458eabdc6f3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go @@ -12,7 +12,6 @@ import ( ) var ( - ErrNotSupportStat = errors.New("stats are not supported for subsystem") ErrNotValidFormat = errors.New("line is not a valid key value format") ) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go index a9a074347336f004d928ffe783289199aa5224ee..8eeedc55b078f203681b3fb99af6a38bfb4c6e92 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go @@ -11,6 +11,7 @@ type ThrottlingData struct { ThrottledTime uint64 `json:"throttled_time,omitempty"` } +// CpuUsage denotes the usage of a CPU. // All CPU stats are aggregate since container inception. type CpuUsage struct { // Total CPU time consumed. @@ -47,13 +48,20 @@ type MemoryStats struct { // usage of memory + swap SwapUsage MemoryData `json:"swap_usage,omitempty"` // usage of kernel memory - KernelUsage MemoryData `json:"kernel_usage,omitempty"` - Stats map[string]uint64 `json:"stats,omitempty"` + KernelUsage MemoryData `json:"kernel_usage,omitempty"` + // usage of kernel TCP memory + KernelTCPUsage MemoryData `json:"kernel_tcp_usage,omitempty"` + // if true, memory usage is accounted for throughout a hierarchy of cgroups. + UseHierarchy bool `json:"use_hierarchy"` + + Stats map[string]uint64 `json:"stats,omitempty"` } type PidsStats struct { // number of pids in the cgroup Current uint64 `json:"current,omitempty"` + // active pids hard limit + Limit uint64 `json:"limit,omitempty"` } type BlkioStatEntry struct { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go index 7de9ae6050bd91e80a85f299829a6c11d6b1355e..a65d8e4432dad7f666aa963bc88b6a1f0df81d68 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux static_build package systemd @@ -43,7 +43,7 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { } func (m *Manager) Set(container *configs.Config) error { - return nil, fmt.Errorf("Systemd not supported") + return fmt.Errorf("Systemd not supported") } func (m *Manager) Freeze(state configs.FreezerState) error { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go index 63a14b4caf38da6060aaf62d595c6dbde20cbc90..e8defe3a1ee26a4ca3dcb3400a151debd7867eee 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!static_build package systemd @@ -6,9 +6,9 @@ import ( "errors" "fmt" "io/ioutil" + "math" "os" "path/filepath" - "strconv" "strings" "sync" "time" @@ -19,6 +19,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/sirupsen/logrus" ) type Manager struct { @@ -67,13 +68,17 @@ var subsystems = subsystemSet{ const ( testScopeWait = 4 + testSliceWait = 4 ) var ( connLock sync.Mutex theConn *systemdDbus.Conn hasStartTransientUnit bool + hasStartTransientSliceUnit bool hasTransientDefaultDependencies bool + hasDelegateScope bool + hasDelegateSlice bool ) func newProp(name string, units interface{}) systemdDbus.Property { @@ -146,18 +151,66 @@ func UseSystemd() bool { // Not critical because of the stop unit logic above. theConn.StopUnit(scope, "replace", nil) - } - return hasStartTransientUnit -} -func getIfaceForUnit(unitName string) string { - if strings.HasSuffix(unitName, ".scope") { - return "Scope" - } - if strings.HasSuffix(unitName, ".service") { - return "Service" + // Assume StartTransientUnit on a scope allows Delegate + hasDelegateScope = true + dlScope := newProp("Delegate", true) + if _, err := theConn.StartTransientUnit(scope, "replace", []systemdDbus.Property{dlScope}, nil); err != nil { + if dbusError, ok := err.(dbus.Error); ok { + if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") { + hasDelegateScope = false + } + } + } + + // Assume we have the ability to start a transient unit as a slice + // This was broken until systemd v229, but has been back-ported on RHEL environments >= 219 + // For details, see: https://bugzilla.redhat.com/show_bug.cgi?id=1370299 + hasStartTransientSliceUnit = true + + // To ensure simple clean-up, we create a slice off the root with no hierarchy + slice := fmt.Sprintf("libcontainer_%d_systemd_test_default.slice", os.Getpid()) + if _, err := theConn.StartTransientUnit(slice, "replace", nil, nil); err != nil { + if _, ok := err.(dbus.Error); ok { + hasStartTransientSliceUnit = false + } + } + + for i := 0; i <= testSliceWait; i++ { + if _, err := theConn.StopUnit(slice, "replace", nil); err != nil { + if dbusError, ok := err.(dbus.Error); ok { + if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") { + hasStartTransientSliceUnit = false + break + } + } + } else { + break + } + time.Sleep(time.Millisecond) + } + + // Not critical because of the stop unit logic above. + theConn.StopUnit(slice, "replace", nil) + + // Assume StartTransientUnit on a slice allows Delegate + hasDelegateSlice = true + dlSlice := newProp("Delegate", true) + if _, err := theConn.StartTransientUnit(slice, "replace", []systemdDbus.Property{dlSlice}, nil); err != nil { + if dbusError, ok := err.(dbus.Error); ok { + // Starting with systemd v237, Delegate is not even a property of slices anymore, + // so the D-Bus call fails with "InvalidArgs" error. + if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") { + hasDelegateSlice = false + } + } + } + + // Not critical because of the stop unit logic above. + theConn.StopUnit(scope, "replace", nil) + theConn.StopUnit(slice, "replace", nil) } - return "Unit" + return hasStartTransientUnit } func (m *Manager) Apply(pid int) error { @@ -189,11 +242,36 @@ func (m *Manager) Apply(pid int) error { slice = c.Parent } - properties = append(properties, - systemdDbus.PropSlice(slice), - systemdDbus.PropDescription("docker container "+c.Name), - newProp("PIDs", []uint32{uint32(pid)}), - ) + properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name)) + + // if we create a slice, the parent is defined via a Wants= + if strings.HasSuffix(unitName, ".slice") { + // This was broken until systemd v229, but has been back-ported on RHEL environments >= 219 + if !hasStartTransientSliceUnit { + return fmt.Errorf("systemd version does not support ability to start a slice as transient unit") + } + properties = append(properties, systemdDbus.PropWants(slice)) + } else { + // otherwise, we use Slice= + properties = append(properties, systemdDbus.PropSlice(slice)) + } + + // only add pid if its valid, -1 is used w/ general slice creation. + if pid != -1 { + properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) + } + + // Check if we can delegate. This is only supported on systemd versions 218 and above. + if strings.HasSuffix(unitName, ".slice") { + if hasDelegateSlice { + // systemd 237 and above no longer allows delegation on a slice + properties = append(properties, newProp("Delegate", true)) + } + } else { + if hasDelegateScope { + properties = append(properties, newProp("Delegate", true)) + } + } // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. @@ -214,7 +292,27 @@ func (m *Manager) Apply(pid int) error { if c.Resources.CpuShares != 0 { properties = append(properties, - newProp("CPUShares", uint64(c.Resources.CpuShares))) + newProp("CPUShares", c.Resources.CpuShares)) + } + + // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd. + if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 { + // corresponds to USEC_INFINITY in systemd + // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd + // always setting a property value ensures we can apply a quota and remove it later + cpuQuotaPerSecUSec := uint64(math.MaxUint64) + if c.Resources.CpuQuota > 0 { + // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota + // (integer percentage of CPU) internally. This means that if a fractional percent of + // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest + // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect. + cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod + if cpuQuotaPerSecUSec%10000 != 0 { + cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000 + } + } + properties = append(properties, + newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec)) } if c.Resources.BlkioWeight != 0 { @@ -222,17 +320,28 @@ func (m *Manager) Apply(pid int) error { newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight))) } - // We need to set kernel memory before processes join cgroup because - // kmem.limit_in_bytes can only be set when the cgroup is empty. - // And swap memory limit needs to be set after memory limit, only - // memory limit is handled by systemd, so it's kind of ugly here. - if c.Resources.KernelMemory > 0 { + if c.Resources.PidsLimit > 0 { + properties = append(properties, + newProp("TasksAccounting", true), + newProp("TasksMax", uint64(c.Resources.PidsLimit))) + } + + // We have to set kernel memory here, as we can't change it once + // processes have been attached to the cgroup. + if c.Resources.KernelMemory != 0 { if err := setKernelMemory(c); err != nil { return err } } - if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil { + statusChan := make(chan string, 1) + if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil { + select { + case <-statusChan: + case <-time.After(time.Second): + logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName) + } + } else if !isUnitExists(err) { return err } @@ -277,15 +386,6 @@ func (m *Manager) GetPaths() map[string]string { return paths } -func writeFile(dir, file, data string) error { - // Normally dir should not be empty, one case is that cgroup subsystem - // is not mounted, we will get empty dir, and we want it fail here. - if dir == "" { - return fmt.Errorf("no such directory for %s.", file) - } - return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700) -} - func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { path, err := getSubsystemPath(c, subsystem) if err != nil { @@ -294,10 +394,9 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { if err := os.MkdirAll(path, 0755); err != nil { return "", err } - if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil { + if err := cgroups.WriteCgroupProc(path, pid); err != nil { return "", err } - return path, nil } @@ -307,7 +406,6 @@ func joinCgroups(c *configs.Cgroup, pid int) error { switch name { case "name=systemd": // let systemd handle this - break case "cpuset": path, err := getSubsystemPath(c, name) if err != nil && !cgroups.IsNotFound(err) { @@ -317,7 +415,6 @@ func joinCgroups(c *configs.Cgroup, pid int) error { if err := s.ApplyDir(path, c, pid); err != nil { return err } - break default: _, err := join(c, name, pid) if err != nil { @@ -339,10 +436,10 @@ func joinCgroups(c *configs.Cgroup, pid int) error { return nil } -// systemd represents slice heirarchy using `-`, so we need to follow suit when +// systemd represents slice hierarchy using `-`, so we need to follow suit when // generating the path of slice. Essentially, test-a-b.slice becomes -// test.slice/test-a.slice/test-a-b.slice. -func expandSlice(slice string) (string, error) { +// /test.slice/test-a.slice/test-a-b.slice. +func ExpandSlice(slice string) (string, error) { suffix := ".slice" // Name has to end with ".slice", but can't be just ".slice". if len(slice) < len(suffix) || !strings.HasSuffix(slice, suffix) { @@ -356,6 +453,10 @@ func expandSlice(slice string) (string, error) { var path, prefix string sliceName := strings.TrimSuffix(slice, suffix) + // if input was -.slice, we should just return root now + if sliceName == "-" { + return "/", nil + } for _, component := range strings.Split(sliceName, "-") { // test--a.slice isn't permitted, nor is -test.slice. if component == "" { @@ -363,30 +464,31 @@ func expandSlice(slice string) (string, error) { } // Append the component to the path and to the prefix. - path += prefix + component + suffix + "/" + path += "/" + prefix + component + suffix prefix += component + "-" } - return path, nil } func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { - mountpoint, err := cgroups.FindCgroupMountpoint(subsystem) + mountpoint, err := cgroups.FindCgroupMountpoint(c.Path, subsystem) if err != nil { return "", err } - initPath, err := cgroups.GetInitCgroupDir(subsystem) + initPath, err := cgroups.GetInitCgroup(subsystem) if err != nil { return "", err } + // if pid 1 is systemd 226 or later, it will be in init.scope, not the root + initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope") slice := "system.slice" if c.Parent != "" { slice = c.Parent } - slice, err = expandSlice(slice) + slice, err = ExpandSlice(slice) if err != nil { return "", err } @@ -447,6 +549,11 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { } func (m *Manager) Set(container *configs.Config) error { + // If Paths are set, then we are just joining cgroups paths + // and there is no need to set any values. + if m.Cgroups.Paths != nil { + return nil + } for _, sys := range subsystems { // Get the subsystem path, but don't error out for not found cgroups. path, err := getSubsystemPath(container.Cgroups, sys.Name()) @@ -468,7 +575,11 @@ func (m *Manager) Set(container *configs.Config) error { } func getUnitName(c *configs.Cgroup) string { - return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name) + // by default, we create a scope unless the user explicitly asks for a slice. + if !strings.HasSuffix(c.Name, ".slice") { + return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name) + } + return c.Name } func setKernelMemory(c *configs.Cgroup) error { @@ -480,8 +591,24 @@ func setKernelMemory(c *configs.Cgroup) error { if err := os.MkdirAll(path, 0755); err != nil { return err } + // do not try to enable the kernel memory if we already have + // tasks in the cgroup. + content, err := ioutil.ReadFile(filepath.Join(path, "tasks")) + if err != nil { + return err + } + if len(content) > 0 { + return nil + } + return fs.EnableKernelMemoryAccounting(path) +} - // This doesn't get called by manager.Set, so we need to do it here. - s := &fs.MemoryGroup{} - return s.SetKernelMemory(path, c) +// isUnitExists returns true if the error is that a systemd unit already exists. +func isUnitExists(err error) bool { + if err != nil { + if dbusError, ok := err.(dbus.Error); ok { + return strings.Contains(dbusError.Name, "org.freedesktop.systemd1.UnitExists") + } + } + return false } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go index 006800dcfae52ceee1b47588d8c6a4c4e44ce1a1..ea571ad937ff26c4fd5a9506ffdfce904f86f4ba 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go @@ -13,61 +13,82 @@ import ( "strings" "time" - "github.com/docker/go-units" + units "github.com/docker/go-units" ) -const cgroupNamePrefix = "name=" +const ( + CgroupNamePrefix = "name=" + CgroupProcesses = "cgroup.procs" +) + +// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt +func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) { + mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem) + return mnt, err +} -// https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt -func FindCgroupMountpoint(subsystem string) (string, error) { +func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string, error) { // We are not using mount.GetMounts() because it's super-inefficient, // parsing it directly sped up x10 times because of not using Sscanf. // It was one of two major performance drawbacks in container start. + if !isSubsystemAvailable(subsystem) { + return "", "", NewNotFoundError(subsystem) + } + f, err := os.Open("/proc/self/mountinfo") if err != nil { - return "", err + return "", "", err } defer f.Close() - scanner := bufio.NewScanner(f) + return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem) +} + +func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsystem string) (string, string, error) { + scanner := bufio.NewScanner(reader) for scanner.Scan() { txt := scanner.Text() - fields := strings.Split(txt, " ") - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { - return fields[4], nil + fields := strings.Fields(txt) + if len(fields) < 5 { + continue + } + if strings.HasPrefix(fields[4], cgroupPath) { + for _, opt := range strings.Split(fields[len(fields)-1], ",") { + if opt == subsystem { + return fields[4], fields[3], nil + } } } } if err := scanner.Err(); err != nil { - return "", err + return "", "", err } - return "", NewNotFoundError(subsystem) + return "", "", NewNotFoundError(subsystem) } -func FindCgroupMountpointAndRoot(subsystem string) (string, string, error) { - f, err := os.Open("/proc/self/mountinfo") +func isSubsystemAvailable(subsystem string) bool { + cgroups, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { - return "", "", err + return false } - defer f.Close() + _, avail := cgroups[subsystem] + return avail +} - scanner := bufio.NewScanner(f) - for scanner.Scan() { - txt := scanner.Text() - fields := strings.Split(txt, " ") - for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if opt == subsystem { - return fields[4], fields[3], nil - } +func GetClosestMountpointAncestor(dir, mountinfo string) string { + deepestMountPoint := "" + for _, mountInfoEntry := range strings.Split(mountinfo, "\n") { + mountInfoParts := strings.Fields(mountInfoEntry) + if len(mountInfoParts) < 5 { + continue + } + mountPoint := mountInfoParts[4] + if strings.HasPrefix(mountPoint, deepestMountPoint) && strings.HasPrefix(dir, mountPoint) { + deepestMountPoint = mountPoint } } - if err := scanner.Err(); err != nil { - return "", "", err - } - - return "", "", NewNotFoundError(subsystem) + return deepestMountPoint } func FindCgroupMountpointDir() (string, error) { @@ -92,7 +113,7 @@ func FindCgroupMountpointDir() (string, error) { } if postSeparatorFields[0] == "cgroup" { - // Check that the mount is properly formated. + // Check that the mount is properly formatted. if numPostFields < 3 { return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) } @@ -113,7 +134,7 @@ type Mount struct { Subsystems []string } -func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) { +func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) { if len(m.Subsystems) == 0 { return "", fmt.Errorf("no subsystem for mount") } @@ -121,16 +142,17 @@ func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) { return getControllerPath(m.Subsystems[0], cgroups) } -func getCgroupMountsHelper(ss map[string]bool, mi io.Reader) ([]Mount, error) { +func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount, error) { res := make([]Mount, 0, len(ss)) scanner := bufio.NewScanner(mi) - for scanner.Scan() { + numFound := 0 + for scanner.Scan() && numFound < len(ss) { txt := scanner.Text() sepIdx := strings.Index(txt, " - ") if sepIdx == -1 { return nil, fmt.Errorf("invalid mountinfo format") } - if txt[sepIdx+3:sepIdx+9] != "cgroup" { + if txt[sepIdx+3:sepIdx+10] == "cgroup2" || txt[sepIdx+3:sepIdx+9] != "cgroup" { continue } fields := strings.Split(txt, " ") @@ -139,14 +161,20 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader) ([]Mount, error) { Root: fields[3], } for _, opt := range strings.Split(fields[len(fields)-1], ",") { - if strings.HasPrefix(opt, cgroupNamePrefix) { - m.Subsystems = append(m.Subsystems, opt[len(cgroupNamePrefix):]) + seen, known := ss[opt] + if !known || (!all && seen) { + continue } - if ss[opt] { - m.Subsystems = append(m.Subsystems, opt) + ss[opt] = true + if strings.HasPrefix(opt, CgroupNamePrefix) { + opt = opt[len(CgroupNamePrefix):] } + m.Subsystems = append(m.Subsystems, opt) + numFound++ + } + if len(m.Subsystems) > 0 || all { + res = append(res, m) } - res = append(res, m) } if err := scanner.Err(); err != nil { return nil, err @@ -154,26 +182,28 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader) ([]Mount, error) { return res, nil } -func GetCgroupMounts() ([]Mount, error) { +// GetCgroupMounts returns the mounts for the cgroup subsystems. +// all indicates whether to return just the first instance or all the mounts. +func GetCgroupMounts(all bool) ([]Mount, error) { f, err := os.Open("/proc/self/mountinfo") if err != nil { return nil, err } defer f.Close() - all, err := GetAllSubsystems() + allSubsystems, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { return nil, err } allMap := make(map[string]bool) - for _, s := range all { - allMap[s] = true + for s := range allSubsystems { + allMap[s] = false } - return getCgroupMountsHelper(allMap, f) + return getCgroupMountsHelper(allMap, f, all) } -// Returns all the cgroup subsystems supported by the kernel +// GetAllSubsystems returns all the cgroup subsystems supported by the kernel func GetAllSubsystems() ([]string, error) { f, err := os.Open("/proc/cgroups") if err != nil { @@ -185,9 +215,6 @@ func GetAllSubsystems() ([]string, error) { s := bufio.NewScanner(f) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } text := s.Text() if text[0] != '#' { parts := strings.Fields(text) @@ -196,11 +223,14 @@ func GetAllSubsystems() ([]string, error) { } } } + if err := s.Err(); err != nil { + return nil, err + } return subsystems, nil } -// Returns the relative path to the cgroup docker is running in. -func GetThisCgroupDir(subsystem string) (string, error) { +// GetOwnCgroup returns the relative path to the cgroup docker is running in. +func GetOwnCgroup(subsystem string) (string, error) { cgroups, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { return "", err @@ -209,8 +239,16 @@ func GetThisCgroupDir(subsystem string) (string, error) { return getControllerPath(subsystem, cgroups) } -func GetInitCgroupDir(subsystem string) (string, error) { +func GetOwnCgroupPath(subsystem string) (string, error) { + cgroup, err := GetOwnCgroup(subsystem) + if err != nil { + return "", err + } + + return getCgroupPathHelper(subsystem, cgroup) +} +func GetInitCgroup(subsystem string) (string, error) { cgroups, err := ParseCgroupFile("/proc/1/cgroup") if err != nil { return "", err @@ -219,8 +257,33 @@ func GetInitCgroupDir(subsystem string) (string, error) { return getControllerPath(subsystem, cgroups) } +func GetInitCgroupPath(subsystem string) (string, error) { + cgroup, err := GetInitCgroup(subsystem) + if err != nil { + return "", err + } + + return getCgroupPathHelper(subsystem, cgroup) +} + +func getCgroupPathHelper(subsystem, cgroup string) (string, error) { + mnt, root, err := FindCgroupMountpointAndRoot("", subsystem) + if err != nil { + return "", err + } + + // This is needed for nested containers, because in /proc/self/cgroup we + // see paths from host, which don't exist in container. + relCgroup, err := filepath.Rel(root, cgroup) + if err != nil { + return "", err + } + + return filepath.Join(mnt, relCgroup), nil +} + func readProcsFile(dir string) ([]int, error) { - f, err := os.Open(filepath.Join(dir, "cgroup.procs")) + f, err := os.Open(filepath.Join(dir, CgroupProcesses)) if err != nil { return nil, err } @@ -243,6 +306,8 @@ func readProcsFile(dir string) ([]int, error) { return out, nil } +// ParseCgroupFile parses the given cgroup file, typically from +// /proc/<pid>/cgroup, into a map of subgroups to cgroup names. func ParseCgroupFile(path string) (map[string]string, error) { f, err := os.Open(path) if err != nil { @@ -250,21 +315,35 @@ func ParseCgroupFile(path string) (map[string]string, error) { } defer f.Close() - s := bufio.NewScanner(f) + return parseCgroupFromReader(f) +} + +// helper function for ParseCgroupFile to make testing easier +func parseCgroupFromReader(r io.Reader) (map[string]string, error) { + s := bufio.NewScanner(r) cgroups := make(map[string]string) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - text := s.Text() - parts := strings.Split(text, ":") + // from cgroups(7): + // /proc/[pid]/cgroup + // ... + // For each cgroup hierarchy ... there is one entry + // containing three colon-separated fields of the form: + // hierarchy-ID:subsystem-list:cgroup-path + parts := strings.SplitN(text, ":", 3) + if len(parts) < 3 { + return nil, fmt.Errorf("invalid cgroup entry: must contain at least two colons: %v", text) + } for _, subs := range strings.Split(parts[1], ",") { cgroups[subs] = parts[2] } } + if err := s.Err(); err != nil { + return nil, err + } + return cgroups, nil } @@ -274,7 +353,7 @@ func getControllerPath(subsystem string, cgroups map[string]string) (string, err return p, nil } - if p, ok := cgroups[cgroupNamePrefix+subsystem]; ok { + if p, ok := cgroups[CgroupNamePrefix+subsystem]; ok { return p, nil } @@ -291,8 +370,7 @@ func PathExists(path string) bool { func EnterPid(cgroupPaths map[string]string, pid int) error { for _, path := range cgroupPaths { if PathExists(path) { - if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), - []byte(strconv.Itoa(pid)), 0700); err != nil { + if err := WriteCgroupProc(path, pid); err != nil { return err } } @@ -326,7 +404,7 @@ func RemovePaths(paths map[string]string) (err error) { return nil } } - return fmt.Errorf("Failed to remove paths: %s", paths) + return fmt.Errorf("Failed to remove paths: %v", paths) } func GetHugePageSize() ([]string, error) { @@ -361,7 +439,7 @@ func GetAllPids(path string) ([]int, error) { // collect pids from all sub-cgroups err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error { dir, file := filepath.Split(p) - if file != "cgroup.procs" { + if file != CgroupProcesses { return nil } if iErr != nil { @@ -376,3 +454,20 @@ func GetAllPids(path string) ([]int, error) { }) return pids, err } + +// WriteCgroupProc writes the specified pid into the cgroup's cgroup.procs file +func WriteCgroupProc(dir string, pid int) error { + // Normally dir should not be empty, one case is that cgroup subsystem + // is not mounted, we will get empty dir, and we want it fail here. + if dir == "" { + return fmt.Errorf("no such directory for %s", CgroupProcesses) + } + + // Don't attach any pid to the cgroup if -1 is specified as a pid + if pid != -1 { + if err := ioutil.WriteFile(filepath.Join(dir, CgroupProcesses), []byte(strconv.Itoa(pid)), 0700); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err) + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go index 47bbd5e2345890704776ec0f9c5059307726998b..fcca9d73a59487003f624c30acd77f0a69f4fa27 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils_test.go @@ -4,6 +4,8 @@ package cgroups import ( "bytes" + "fmt" + "reflect" "strings" "testing" ) @@ -91,6 +93,90 @@ const systemdMountinfo = `115 83 0:32 / / rw,relatime - aufs none rw,si=c0bd3d3, 136 117 0:12 /1 /dev/console rw,nosuid,noexec,relatime - devpts none rw,gid=5,mode=620,ptmxmode=000 84 115 0:40 / /tmp rw,relatime - tmpfs none rw` +const bedrockMountinfo = `120 17 0:28 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:16 - tmpfs tmpfs ro,mode=755 +124 28 0:28 / /bedrock/strata/arch/sys/fs/cgroup rw,nosuid,nodev,noexec shared:16 - tmpfs tmpfs ro,mode=755 +123 53 0:28 / /bedrock/strata/fallback/sys/fs/cgroup rw,nosuid,nodev,noexec shared:16 - tmpfs tmpfs ro,mode=755 +122 71 0:28 / /bedrock/strata/gentoo/sys/fs/cgroup rw,nosuid,nodev,noexec shared:16 - tmpfs tmpfs ro,mode=755 +121 89 0:28 / /bedrock/strata/kde/sys/fs/cgroup rw,nosuid,nodev,noexec shared:16 - tmpfs tmpfs ro,mode=755 +125 120 0:29 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +129 124 0:29 / /bedrock/strata/arch/sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +128 123 0:29 / /bedrock/strata/fallback/sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +127 122 0:29 / /bedrock/strata/gentoo/sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +126 121 0:29 / /bedrock/strata/kde/sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +140 120 0:32 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:48 - cgroup cgroup rw,net_cls,net_prio +144 124 0:32 / /bedrock/strata/arch/sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:48 - cgroup cgroup rw,net_cls,net_prio +143 123 0:32 / /bedrock/strata/fallback/sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:48 - cgroup cgroup rw,net_cls,net_prio +142 122 0:32 / /bedrock/strata/gentoo/sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:48 - cgroup cgroup rw,net_cls,net_prio +141 121 0:32 / /bedrock/strata/kde/sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:48 - cgroup cgroup rw,net_cls,net_prio +145 120 0:33 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:49 - cgroup cgroup rw,blkio +149 124 0:33 / /bedrock/strata/arch/sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:49 - cgroup cgroup rw,blkio +148 123 0:33 / /bedrock/strata/fallback/sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:49 - cgroup cgroup rw,blkio +147 122 0:33 / /bedrock/strata/gentoo/sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:49 - cgroup cgroup rw,blkio +146 121 0:33 / /bedrock/strata/kde/sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:49 - cgroup cgroup rw,blkio +150 120 0:34 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:50 - cgroup cgroup rw,cpu,cpuacct +154 124 0:34 / /bedrock/strata/arch/sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:50 - cgroup cgroup rw,cpu,cpuacct +153 123 0:34 / /bedrock/strata/fallback/sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:50 - cgroup cgroup rw,cpu,cpuacct +152 122 0:34 / /bedrock/strata/gentoo/sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:50 - cgroup cgroup rw,cpu,cpuacct +151 121 0:34 / /bedrock/strata/kde/sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:50 - cgroup cgroup rw,cpu,cpuacct +155 120 0:35 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:51 - cgroup cgroup rw,cpuset +159 124 0:35 / /bedrock/strata/arch/sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:51 - cgroup cgroup rw,cpuset +158 123 0:35 / /bedrock/strata/fallback/sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:51 - cgroup cgroup rw,cpuset +157 122 0:35 / /bedrock/strata/gentoo/sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:51 - cgroup cgroup rw,cpuset +156 121 0:35 / /bedrock/strata/kde/sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:51 - cgroup cgroup rw,cpuset +160 120 0:36 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:52 - cgroup cgroup rw,devices +164 124 0:36 / /bedrock/strata/arch/sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:52 - cgroup cgroup rw,devices +163 123 0:36 / /bedrock/strata/fallback/sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:52 - cgroup cgroup rw,devices +162 122 0:36 / /bedrock/strata/gentoo/sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:52 - cgroup cgroup rw,devices +161 121 0:36 / /bedrock/strata/kde/sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:52 - cgroup cgroup rw,devices +165 120 0:37 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:53 - cgroup cgroup rw,memory +169 124 0:37 / /bedrock/strata/arch/sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:53 - cgroup cgroup rw,memory +168 123 0:37 / /bedrock/strata/fallback/sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:53 - cgroup cgroup rw,memory +167 122 0:37 / /bedrock/strata/gentoo/sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:53 - cgroup cgroup rw,memory +166 121 0:37 / /bedrock/strata/kde/sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:53 - cgroup cgroup rw,memory +170 120 0:38 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:54 - cgroup cgroup rw,freezer +174 124 0:38 / /bedrock/strata/arch/sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:54 - cgroup cgroup rw,freezer +173 123 0:38 / /bedrock/strata/fallback/sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:54 - cgroup cgroup rw,freezer +172 122 0:38 / /bedrock/strata/gentoo/sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:54 - cgroup cgroup rw,freezer +171 121 0:38 / /bedrock/strata/kde/sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:54 - cgroup cgroup rw,freezer +175 120 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:55 - cgroup cgroup rw,pids +179 124 0:39 / /bedrock/strata/arch/sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:55 - cgroup cgroup rw,pids +178 123 0:39 / /bedrock/strata/fallback/sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:55 - cgroup cgroup rw,pids +177 122 0:39 / /bedrock/strata/gentoo/sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:55 - cgroup cgroup rw,pids +176 121 0:39 / /bedrock/strata/kde/sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:55 - cgroup cgroup rw,pids +180 120 0:40 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:56 - cgroup cgroup rw,perf_event +184 124 0:40 / /bedrock/strata/arch/sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:56 - cgroup cgroup rw,perf_event +183 123 0:40 / /bedrock/strata/fallback/sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:56 - cgroup cgroup rw,perf_event +182 122 0:40 / /bedrock/strata/gentoo/sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:56 - cgroup cgroup rw,perf_event +181 121 0:40 / /bedrock/strata/kde/sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:56 - cgroup cgroup rw,perf_event` + +const cgroup2Mountinfo = `18 64 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel +19 64 0:4 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw +20 64 0:6 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8171204k,nr_inodes=2042801,mode=755 +21 18 0:19 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw +22 20 0:20 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel +23 20 0:21 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000 +24 64 0:22 / /run rw,nosuid,nodev shared:24 - tmpfs tmpfs rw,seclabel,mode=755 +25 18 0:23 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:8 - tmpfs tmpfs ro,seclabel,mode=755 +26 25 0:24 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:9 - cgroup2 cgroup rw +27 18 0:25 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw,seclabel +28 18 0:26 / /sys/firmware/efi/efivars rw,nosuid,nodev,noexec,relatime shared:21 - efivarfs efivarfs rw +29 25 0:27 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,cpu,cpuacct +30 25 0:28 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,memory +31 25 0:29 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,net_cls,net_prio +32 25 0:30 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,blkio +33 25 0:31 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,perf_event +34 25 0:32 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,hugetlb +35 25 0:33 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,freezer +36 25 0:34 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpuset +37 25 0:35 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,devices +38 25 0:36 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,pids +61 18 0:37 / /sys/kernel/config rw,relatime shared:22 - configfs configfs rw +64 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/fedora_dhcp--16--129-root rw,seclabel,data=ordered +39 18 0:17 / /sys/fs/selinux rw,relatime shared:23 - selinuxfs selinuxfs rw +40 20 0:16 / /dev/mqueue rw,relatime shared:25 - mqueue mqueue rw,seclabel +41 20 0:39 / /dev/hugepages rw,relatime shared:26 - hugetlbfs hugetlbfs rw,seclabel +` + func TestGetCgroupMounts(t *testing.T) { type testData struct { mountInfo string @@ -102,37 +188,52 @@ func TestGetCgroupMounts(t *testing.T) { mountInfo: fedoraMountinfo, root: "/", subsystems: map[string]bool{ - "cpuset": true, - "cpu": true, - "cpuacct": true, - "memory": true, - "devices": true, - "freezer": true, - "net_cls": true, - "blkio": true, - "perf_event": true, - "hugetlb": true, + "cpuset": false, + "cpu": false, + "cpuacct": false, + "memory": false, + "devices": false, + "freezer": false, + "net_cls": false, + "blkio": false, + "perf_event": false, + "hugetlb": false, }, }, { mountInfo: systemdMountinfo, root: "/system.slice/docker-dc4eaa1a34ec4d593bc0125d31eea823a1d76ae483aeb1409cca80304e34da2e.scope", subsystems: map[string]bool{ - "cpuset": true, - "cpu": true, - "cpuacct": true, - "memory": true, - "devices": true, - "freezer": true, - "net_cls": true, - "blkio": true, - "perf_event": true, + "cpuset": false, + "cpu": false, + "cpuacct": false, + "memory": false, + "devices": false, + "freezer": false, + "net_cls": false, + "blkio": false, + "perf_event": false, + }, + }, + { + mountInfo: bedrockMountinfo, + root: "/", + subsystems: map[string]bool{ + "cpuset": false, + "cpu": false, + "cpuacct": false, + "memory": false, + "devices": false, + "freezer": false, + "net_cls": false, + "blkio": false, + "perf_event": false, }, }, } for _, td := range testTable { mi := bytes.NewBufferString(td.mountInfo) - cgMounts, err := getCgroupMountsHelper(td.subsystems, mi) + cgMounts, err := getCgroupMountsHelper(td.subsystems, mi, false) if err != nil { t.Fatal(err) } @@ -169,24 +270,154 @@ func TestGetCgroupMounts(t *testing.T) { func BenchmarkGetCgroupMounts(b *testing.B) { subsystems := map[string]bool{ - "cpuset": true, - "cpu": true, - "cpuacct": true, - "memory": true, - "devices": true, - "freezer": true, - "net_cls": true, - "blkio": true, - "perf_event": true, - "hugetlb": true, + "cpuset": false, + "cpu": false, + "cpuacct": false, + "memory": false, + "devices": false, + "freezer": false, + "net_cls": false, + "blkio": false, + "perf_event": false, + "hugetlb": false, } b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() mi := bytes.NewBufferString(fedoraMountinfo) b.StartTimer() - if _, err := getCgroupMountsHelper(subsystems, mi); err != nil { + if _, err := getCgroupMountsHelper(subsystems, mi, false); err != nil { b.Fatal(err) } } } + +func TestParseCgroupString(t *testing.T) { + testCases := []struct { + input string + expectedError error + expectedOutput map[string]string + }{ + { + // Taken from a CoreOS instance running systemd 225 with CPU/Mem + // accounting enabled in systemd + input: `9:blkio:/ +8:freezer:/ +7:perf_event:/ +6:devices:/system.slice/system-sshd.slice +5:cpuset:/ +4:cpu,cpuacct:/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service +3:net_cls,net_prio:/ +2:memory:/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service +1:name=systemd:/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service`, + expectedOutput: map[string]string{ + "name=systemd": "/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service", + "blkio": "/", + "freezer": "/", + "perf_event": "/", + "devices": "/system.slice/system-sshd.slice", + "cpuset": "/", + "cpu": "/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service", + "cpuacct": "/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service", + "net_cls": "/", + "net_prio": "/", + "memory": "/system.slice/system-sshd.slice/sshd@126-10.240.0.15:22-xxx.yyy.zzz.aaa:33678.service", + }, + }, + { + input: `malformed input`, + expectedError: fmt.Errorf(`invalid cgroup entry: must contain at least two colons: malformed input`), + }, + } + + for ndx, testCase := range testCases { + out, err := parseCgroupFromReader(strings.NewReader(testCase.input)) + if err != nil { + if testCase.expectedError == nil || testCase.expectedError.Error() != err.Error() { + t.Errorf("%v: expected error %v, got error %v", ndx, testCase.expectedError, err) + } + } else { + if !reflect.DeepEqual(testCase.expectedOutput, out) { + t.Errorf("%v: expected output %v, got error %v", ndx, testCase.expectedOutput, out) + } + } + } + +} + +func TestIgnoreCgroup2Mount(t *testing.T) { + subsystems := map[string]bool{ + "cpuset": false, + "cpu": false, + "cpuacct": false, + "memory": false, + "devices": false, + "freezer": false, + "net_cls": false, + "blkio": false, + "perf_event": false, + "pids": false, + "name=systemd": false, + } + + mi := bytes.NewBufferString(cgroup2Mountinfo) + cgMounts, err := getCgroupMountsHelper(subsystems, mi, false) + if err != nil { + t.Fatal(err) + } + for _, m := range cgMounts { + if m.Mountpoint == "/sys/fs/cgroup/systemd" { + t.Errorf("parsed a cgroup2 mount at /sys/fs/cgroup/systemd instead of ignoring it") + } + } +} + +func TestGetClosestMountpointAncestor(t *testing.T) { + fakeMountInfo := ` 18 24 0:17 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw +100 99 1:31 / /foo/bar rw,relatime - fake fake rw,fake +100 99 1:31 / /foo/bar/baz2 rw,relatime - fake fake rw,fake +100 99 1:31 / /foo/bar/baz rw,relatime - fake fake rw,fake +100 99 1:31 / /foo/bar/bazza rw,relatime - fake fake rw,fake +100 99 1:31 / /foo/bar/baz3 rw,relatime - fake fake rw,fake +100 99 1:31 / /foo rw,relatime - fake fake rw,fake +100 99 1:31 / /unrelated rw,relatime - fake fake rw,fake +100 99 1:31 / / rw,relatime - fake fake rw,fake +` + testCases := []struct { + input string + output string + }{ + {input: "/foo/bar/baz/a/b/c", output: "/foo/bar/baz"}, + {input: "/foo/bar/baz", output: "/foo/bar/baz"}, + {input: "/foo/bar/bazza", output: "/foo/bar/bazza"}, + {input: "/a/b/c/d", output: "/"}, + } + + for _, c := range testCases { + mountpoint := GetClosestMountpointAncestor(c.input, fakeMountInfo) + if mountpoint != c.output { + t.Errorf("expected %s, got %s", c.output, mountpoint) + } + } +} + +func TestFindCgroupMountpointAndRoot(t *testing.T) { + fakeMountInfo := ` +35 27 0:29 / /foo rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,devices +35 27 0:29 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,devices +` + testCases := []struct { + cgroupPath string + output string + }{ + {cgroupPath: "/sys/fs", output: "/sys/fs/cgroup/devices"}, + {cgroupPath: "", output: "/foo"}, + } + + for _, c := range testCases { + mountpoint, _, _ := findCgroupMountpointAndRootFromReader(strings.NewReader(fakeMountInfo), c.cgroupPath, "devices") + if mountpoint != c.output { + t.Errorf("expected %s, got %s", c.output, mountpoint) + } + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go deleted file mode 100644 index c7bdf1f60a01f3f72dd20c7403253128638d8af3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build linux,!go1.5 - -package libcontainer - -import "syscall" - -// GidMappingsEnableSetgroups was added in Go 1.5, so do nothing when building -// with earlier versions -func enableSetgroups(sys *syscall.SysProcAttr) { -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go similarity index 86% rename from vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go rename to vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go index 2ea00658f51a2a6606355231f2cbf94661c0703a..e15a662f52288966e6a88fbb85c60f5e7705f240 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go @@ -1,5 +1,3 @@ -// +build linux freebsd - package configs type FreezerState string @@ -22,7 +20,7 @@ type Cgroup struct { // The path is assumed to be relative to the host system cgroup mountpoint. Path string `json:"path"` - // ScopePrefix decribes prefix for the scope name + // ScopePrefix describes prefix for the scope name ScopePrefix string `json:"scope_prefix"` // Paths represent the absolute cgroups paths to join. @@ -36,7 +34,7 @@ type Cgroup struct { type Resources struct { // If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list. // Deprecated - AllowAllDevices bool `json:"allow_all_devices,omitempty"` + AllowAllDevices *bool `json:"allow_all_devices,omitempty"` // Deprecated AllowedDevices []*Device `json:"allowed_devices,omitempty"` // Deprecated @@ -56,20 +54,23 @@ type Resources struct { // Kernel memory limit (in bytes) KernelMemory int64 `json:"kernel_memory"` + // Kernel memory limit for TCP use (in bytes) + KernelMemoryTCP int64 `json:"kernel_memory_tcp"` + // CPU shares (relative weight vs. other containers) - CpuShares int64 `json:"cpu_shares"` + CpuShares uint64 `json:"cpu_shares"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period. CpuQuota int64 `json:"cpu_quota"` // CPU period to be used for hardcapping (in usecs). 0 to use system default. - CpuPeriod int64 `json:"cpu_period"` + CpuPeriod uint64 `json:"cpu_period"` // How many time CPU will use in realtime scheduling (in usecs). - CpuRtRuntime int64 `json:"cpu_quota"` + CpuRtRuntime int64 `json:"cpu_rt_quota"` // CPU period to be used for realtime scheduling (in usecs). - CpuRtPeriod int64 `json:"cpu_period"` + CpuRtPeriod uint64 `json:"cpu_rt_period"` // CPU to use CpusetCpus string `json:"cpuset_cpus"` @@ -92,7 +93,7 @@ type Resources struct { // IO read rate limit per cgroup per device, bytes per second. BlkioThrottleReadBpsDevice []*ThrottleDevice `json:"blkio_throttle_read_bps_device"` - // IO write rate limit per cgroup per divice, bytes per second. + // IO write rate limit per cgroup per device, bytes per second. BlkioThrottleWriteBpsDevice []*ThrottleDevice `json:"blkio_throttle_write_bps_device"` // IO read rate limit per cgroup per device, IO per second. @@ -111,11 +112,11 @@ type Resources struct { OomKillDisable bool `json:"oom_kill_disable"` // Tuning swappiness behaviour per cgroup - MemorySwappiness *int64 `json:"memory_swappiness"` + MemorySwappiness *uint64 `json:"memory_swappiness"` // Set priority of network traffic for container NetPrioIfpriomap []*IfPrioMap `json:"net_prio_ifpriomap"` // Set class identifier for container's network packets - NetClsClassid string `json:"net_cls_classid"` + NetClsClassid uint32 `json:"net_cls_classid_u"` } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go deleted file mode 100644 index 95e2830a43602596f7e03d06575dba710d0d4b12..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go +++ /dev/null @@ -1,6 +0,0 @@ -// +build !windows,!linux,!freebsd - -package configs - -type Cgroup struct { -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 3b6d5c07720b7a0b68e6d2e5c9aed97f505965c0..7728522fef60d5d1142a5f6b5fc33245b6a50e49 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -3,7 +3,11 @@ package configs import ( "bytes" "encoding/json" + "fmt" "os/exec" + "time" + + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" ) @@ -31,7 +35,7 @@ type Seccomp struct { Syscalls []*Syscall `json:"syscalls"` } -// An action to be taken upon rule match in Seccomp +// Action is taken upon rule match in Seccomp type Action int const ( @@ -42,7 +46,7 @@ const ( Trace ) -// A comparison operator to be used when matching syscall arguments in Seccomp +// Operator is a comparison operator to be used when matching syscall arguments in Seccomp type Operator int const ( @@ -55,7 +59,7 @@ const ( MaskEqualTo ) -// A rule to match a specific syscall argument in Seccomp +// Arg is a rule to match a specific syscall argument in Seccomp type Arg struct { Index uint `json:"index"` Value uint64 `json:"value"` @@ -63,7 +67,7 @@ type Arg struct { Op Operator `json:"op"` } -// An rule to match a syscall in Seccomp +// Syscall is a rule to match a syscall in Seccomp type Syscall struct { Name string `json:"name"` Action Action `json:"action"` @@ -83,11 +87,6 @@ type Config struct { // that the parent process dies. ParentDeathSignal int `json:"parent_death_signal"` - // PivotDir allows a custom directory inside the container's root filesystem to be used as pivot, when NoPivotRoot is not set. - // When a custom PivotDir not set, a temporary dir inside the root filesystem will be used. The pivot dir needs to be writeable. - // This is required when using read only root filesystems. In these cases, a read/writeable path can be (bind) mounted somewhere inside the root filesystem to act as pivot. - PivotDir string `json:"pivot_dir"` - // Path to a directory containing the container's root filesystem. Rootfs string `json:"rootfs"` @@ -115,8 +114,8 @@ type Config struct { Namespaces Namespaces `json:"namespaces"` // Capabilities specify the capabilities to keep when executing the process inside the container - // All capbilities not specified will be dropped from the processes capability mask - Capabilities []string `json:"capabilities"` + // All capabilities not specified will be dropped from the processes capability mask + Capabilities *Capabilities `json:"capabilities"` // Networks specifies the container's network setup to be created Networks []*Network `json:"networks"` @@ -142,13 +141,10 @@ type Config struct { // OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores // for a process. Valid values are between the range [-1000, '1000'], where processes with - // higher scores are preferred for being killed. + // higher scores are preferred for being killed. If it is unset then we don't touch the current + // value. // More information about kernel oom score calculation here: https://lwn.net/Articles/317814/ - OomScoreAdj int `json:"oom_score_adj"` - - // AdditionalGroups specifies the gids that should be added to supplementary groups - // in addition to those that the user belongs to. - AdditionalGroups []string `json:"additional_groups"` + OomScoreAdj *int `json:"oom_score_adj,omitempty"` // UidMappings is an array of User ID mappings for User Namespaces UidMappings []IDMap `json:"uid_mappings"` @@ -185,6 +181,24 @@ type Config struct { // Labels are user defined metadata that is stored in the config and populated on the state Labels []string `json:"labels"` + + // NoNewKeyring will not allocated a new session keyring for the container. It will use the + // callers keyring in this case. + NoNewKeyring bool `json:"no_new_keyring"` + + // IntelRdt specifies settings for Intel RDT group that the container is placed into + // to limit the resources (e.g., L3 cache, memory bandwidth) the container has available + IntelRdt *IntelRdt `json:"intel_rdt,omitempty"` + + // RootlessEUID is set when the runc was launched with non-zero EUID. + // Note that RootlessEUID is set to false when launched with EUID=0 in userns. + // When RootlessEUID is set, runc creates a new userns for the container. + // (config.json needs to contain userns settings) + RootlessEUID bool `json:"rootless_euid,omitempty"` + + // RootlessCgroups is set when unlikely to have the full access to cgroups. + // When RootlessCgroups is set, cgroups errors are ignored. + RootlessCgroups bool `json:"rootless_cgroups,omitempty"` } type Hooks struct { @@ -199,6 +213,19 @@ type Hooks struct { Poststop []Hook } +type Capabilities struct { + // Bounding is the set of capabilities checked by the kernel. + Bounding []string + // Effective is the set of capabilities checked by the kernel. + Effective []string + // Inheritable is the capabilities preserved across execve. + Inheritable []string + // Permitted is the limiting superset for effective capabilities. + Permitted []string + // Ambient is the ambient set of capabilities that are kept. + Ambient []string +} + func (hooks *Hooks) UnmarshalJSON(b []byte) error { var state struct { Prestart []CommandHook @@ -245,42 +272,35 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) { }) } -// HookState is the payload provided to a hook on execution. -type HookState struct { - Version string `json:"version"` - ID string `json:"id"` - Pid int `json:"pid"` - Root string `json:"root"` -} - type Hook interface { // Run executes the hook with the provided state. - Run(HookState) error + Run(*specs.State) error } -// NewFunctionHooks will call the provided function when the hook is run. -func NewFunctionHook(f func(HookState) error) FuncHook { +// NewFunctionHook will call the provided function when the hook is run. +func NewFunctionHook(f func(*specs.State) error) FuncHook { return FuncHook{ run: f, } } type FuncHook struct { - run func(HookState) error + run func(*specs.State) error } -func (f FuncHook) Run(s HookState) error { +func (f FuncHook) Run(s *specs.State) error { return f.run(s) } type Command struct { - Path string `json:"path"` - Args []string `json:"args"` - Env []string `json:"env"` - Dir string `json:"dir"` + Path string `json:"path"` + Args []string `json:"args"` + Env []string `json:"env"` + Dir string `json:"dir"` + Timeout *time.Duration `json:"timeout"` } -// NewCommandHooks will execute the provided command when the hook is run. +// NewCommandHook will execute the provided command when the hook is run. func NewCommandHook(cmd Command) CommandHook { return CommandHook{ Command: cmd, @@ -291,16 +311,43 @@ type CommandHook struct { Command } -func (c Command) Run(s HookState) error { +func (c Command) Run(s *specs.State) error { b, err := json.Marshal(s) if err != nil { return err } + var stdout, stderr bytes.Buffer cmd := exec.Cmd{ - Path: c.Path, - Args: c.Args, - Env: c.Env, - Stdin: bytes.NewReader(b), + Path: c.Path, + Args: c.Args, + Env: c.Env, + Stdin: bytes.NewReader(b), + Stdout: &stdout, + Stderr: &stderr, + } + if err := cmd.Start(); err != nil { + return err + } + errC := make(chan error, 1) + go func() { + err := cmd.Wait() + if err != nil { + err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String()) + } + errC <- err + }() + var timerCh <-chan time.Time + if c.Timeout != nil { + timer := time.NewTimer(*c.Timeout) + defer timer.Stop() + timerCh = timer.C + } + select { + case err := <-errC: + return err + case <-timerCh: + cmd.Process.Kill() + cmd.Wait() + return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds()) } - return cmd.Run() } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..07da10804540de7292d918347f755367d985b23b --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go @@ -0,0 +1,61 @@ +package configs + +import "fmt" + +// HostUID gets the translated uid for the process on host which could be +// different when user namespaces are enabled. +func (c Config) HostUID(containerId int) (int, error) { + if c.Namespaces.Contains(NEWUSER) { + if c.UidMappings == nil { + return -1, fmt.Errorf("User namespaces enabled, but no uid mappings found.") + } + id, found := c.hostIDFromMapping(containerId, c.UidMappings) + if !found { + return -1, fmt.Errorf("User namespaces enabled, but no user mapping found.") + } + return id, nil + } + // Return unchanged id. + return containerId, nil +} + +// HostRootUID gets the root uid for the process on host which could be non-zero +// when user namespaces are enabled. +func (c Config) HostRootUID() (int, error) { + return c.HostUID(0) +} + +// HostGID gets the translated gid for the process on host which could be +// different when user namespaces are enabled. +func (c Config) HostGID(containerId int) (int, error) { + if c.Namespaces.Contains(NEWUSER) { + if c.GidMappings == nil { + return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.") + } + id, found := c.hostIDFromMapping(containerId, c.GidMappings) + if !found { + return -1, fmt.Errorf("User namespaces enabled, but no group mapping found.") + } + return id, nil + } + // Return unchanged id. + return containerId, nil +} + +// HostRootGID gets the root gid for the process on host which could be non-zero +// when user namespaces are enabled. +func (c Config) HostRootGID() (int, error) { + return c.HostGID(0) +} + +// Utility function that gets a host ID for a container ID from user namespace map +// if that ID is present in the map. +func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) { + for _, m := range uMap { + if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) { + hostID := m.HostID + (containerID - m.ContainerID) + return hostID, true + } + } + return -1, false +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux_test.go similarity index 71% rename from vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go rename to vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux_test.go index 27d07d4e816b02633397d54bbd3d281752b353df..9c5f0febed6b5282be73052f0a95f09db4707dbc 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux_test.go @@ -1,5 +1,3 @@ -// +build linux freebsd - package configs import ( @@ -10,30 +8,6 @@ import ( "testing" ) -// Checks whether the expected capability is specified in the capabilities. -func contains(expected string, values []string) bool { - for _, v := range values { - if v == expected { - return true - } - } - return false -} - -func containsDevice(expected *Device, values []*Device) bool { - for _, d := range values { - if d.Path == expected.Path && - d.Permissions == expected.Permissions && - d.FileMode == expected.FileMode && - d.Major == expected.Major && - d.Minor == expected.Minor && - d.Type == expected.Type { - return true - } - } - return false -} - func loadConfig(name string) (*Config, error) { f, err := os.Open(filepath.Join("../sample_configs", name)) if err != nil { @@ -89,11 +63,11 @@ func TestRemoveNamespace(t *testing.T) { } } -func TestHostUIDNoUSERNS(t *testing.T) { +func TestHostRootUIDNoUSERNS(t *testing.T) { config := &Config{ Namespaces: Namespaces{}, } - uid, err := config.HostUID() + uid, err := config.HostRootUID() if err != nil { t.Fatal(err) } @@ -102,7 +76,7 @@ func TestHostUIDNoUSERNS(t *testing.T) { } } -func TestHostUIDWithUSERNS(t *testing.T) { +func TestHostRootUIDWithUSERNS(t *testing.T) { config := &Config{ Namespaces: Namespaces{{Type: NEWUSER}}, UidMappings: []IDMap{ @@ -113,7 +87,7 @@ func TestHostUIDWithUSERNS(t *testing.T) { }, }, } - uid, err := config.HostUID() + uid, err := config.HostRootUID() if err != nil { t.Fatal(err) } @@ -122,11 +96,11 @@ func TestHostUIDWithUSERNS(t *testing.T) { } } -func TestHostGIDNoUSERNS(t *testing.T) { +func TestHostRootGIDNoUSERNS(t *testing.T) { config := &Config{ Namespaces: Namespaces{}, } - uid, err := config.HostGID() + uid, err := config.HostRootGID() if err != nil { t.Fatal(err) } @@ -135,7 +109,7 @@ func TestHostGIDNoUSERNS(t *testing.T) { } } -func TestHostGIDWithUSERNS(t *testing.T) { +func TestHostRootGIDWithUSERNS(t *testing.T) { config := &Config{ Namespaces: Namespaces{{Type: NEWUSER}}, GidMappings: []IDMap{ @@ -146,7 +120,7 @@ func TestHostGIDWithUSERNS(t *testing.T) { }, }, } - uid, err := config.HostGID() + uid, err := config.HostRootGID() if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_test.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c89a764de1adae7ccf8c941bb109391ee5ef9257 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_test.go @@ -0,0 +1,195 @@ +package configs_test + +import ( + "encoding/json" + "fmt" + "os" + "reflect" + "testing" + "time" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" +) + +func TestUnmarshalHooks(t *testing.T) { + timeout := time.Second + + prestartCmd := configs.NewCommandHook(configs.Command{ + Path: "/var/vcap/hooks/prestart", + Args: []string{"--pid=123"}, + Env: []string{"FOO=BAR"}, + Dir: "/var/vcap", + Timeout: &timeout, + }) + prestart, err := json.Marshal(prestartCmd.Command) + if err != nil { + t.Fatal(err) + } + + hook := configs.Hooks{} + err = hook.UnmarshalJSON([]byte(fmt.Sprintf(`{"Prestart" :[%s]}`, prestart))) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(hook.Prestart[0], prestartCmd) { + t.Errorf("Expected prestart to equal %+v but it was %+v", + prestartCmd, hook.Prestart[0]) + } +} + +func TestUnmarshalHooksWithInvalidData(t *testing.T) { + hook := configs.Hooks{} + err := hook.UnmarshalJSON([]byte(`{invalid-json}`)) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestMarshalHooks(t *testing.T) { + timeout := time.Second + + prestartCmd := configs.NewCommandHook(configs.Command{ + Path: "/var/vcap/hooks/prestart", + Args: []string{"--pid=123"}, + Env: []string{"FOO=BAR"}, + Dir: "/var/vcap", + Timeout: &timeout, + }) + + hook := configs.Hooks{ + Prestart: []configs.Hook{prestartCmd}, + } + hooks, err := hook.MarshalJSON() + if err != nil { + t.Fatal(err) + } + + h := `{"poststart":null,"poststop":null,"prestart":[{"path":"/var/vcap/hooks/prestart","args":["--pid=123"],"env":["FOO=BAR"],"dir":"/var/vcap","timeout":1000000000}]}` + if string(hooks) != h { + t.Errorf("Expected hooks %s to equal %s", string(hooks), h) + } +} + +func TestMarshalUnmarshalHooks(t *testing.T) { + timeout := time.Second + + prestart := configs.NewCommandHook(configs.Command{ + Path: "/var/vcap/hooks/prestart", + Args: []string{"--pid=123"}, + Env: []string{"FOO=BAR"}, + Dir: "/var/vcap", + Timeout: &timeout, + }) + + hook := configs.Hooks{ + Prestart: []configs.Hook{prestart}, + } + hooks, err := hook.MarshalJSON() + if err != nil { + t.Fatal(err) + } + + umMhook := configs.Hooks{} + err = umMhook.UnmarshalJSON(hooks) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(umMhook.Prestart[0], prestart) { + t.Errorf("Expected hooks to be equal after mashaling -> unmarshaling them: %+v, %+v", umMhook.Prestart[0], prestart) + } +} + +func TestMarshalHooksWithUnexpectedType(t *testing.T) { + fHook := configs.NewFunctionHook(func(*specs.State) error { + return nil + }) + hook := configs.Hooks{ + Prestart: []configs.Hook{fHook}, + } + hooks, err := hook.MarshalJSON() + if err != nil { + t.Fatal(err) + } + + h := `{"poststart":null,"poststop":null,"prestart":null}` + if string(hooks) != h { + t.Errorf("Expected hooks %s to equal %s", string(hooks), h) + } +} + +func TestFuncHookRun(t *testing.T) { + state := &specs.State{ + Version: "1", + ID: "1", + Status: "created", + Pid: 1, + Bundle: "/bundle", + } + + fHook := configs.NewFunctionHook(func(s *specs.State) error { + if !reflect.DeepEqual(state, s) { + t.Errorf("Expected state %+v to equal %+v", state, s) + } + return nil + }) + + fHook.Run(state) +} + +func TestCommandHookRun(t *testing.T) { + state := &specs.State{ + Version: "1", + ID: "1", + Status: "created", + Pid: 1, + Bundle: "/bundle", + } + timeout := time.Second + + cmdHook := configs.NewCommandHook(configs.Command{ + Path: os.Args[0], + Args: []string{os.Args[0], "-test.run=TestHelperProcess"}, + Env: []string{"FOO=BAR"}, + Dir: "/", + Timeout: &timeout, + }) + + err := cmdHook.Run(state) + if err != nil { + t.Errorf(fmt.Sprintf("Expected error to not occur but it was %+v", err)) + } +} + +func TestCommandHookRunTimeout(t *testing.T) { + state := &specs.State{ + Version: "1", + ID: "1", + Status: "created", + Pid: 1, + Bundle: "/bundle", + } + timeout := (10 * time.Millisecond) + + cmdHook := configs.NewCommandHook(configs.Command{ + Path: os.Args[0], + Args: []string{os.Args[0], "-test.run=TestHelperProcessWithTimeout"}, + Env: []string{"FOO=BAR"}, + Dir: "/", + Timeout: &timeout, + }) + + err := cmdHook.Run(state) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestHelperProcess(*testing.T) { + fmt.Println("Helper Process") + os.Exit(0) +} +func TestHelperProcessWithTimeout(*testing.T) { + time.Sleep(time.Second) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go deleted file mode 100644 index c447f3ef29f4d3669d0f435258d7e9fc3763a75e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build freebsd linux - -package configs - -import "fmt" - -// Gets the root uid for the process on host which could be non-zero -// when user namespaces are enabled. -func (c Config) HostUID() (int, error) { - if c.Namespaces.Contains(NEWUSER) { - if c.UidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no user mappings found.") - } - id, found := c.hostIDFromMapping(0, c.UidMappings) - if !found { - return -1, fmt.Errorf("User namespaces enabled, but no root user mapping found.") - } - return id, nil - } - // Return default root uid 0 - return 0, nil -} - -// Gets the root gid for the process on host which could be non-zero -// when user namespaces are enabled. -func (c Config) HostGID() (int, error) { - if c.Namespaces.Contains(NEWUSER) { - if c.GidMappings == nil { - return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.") - } - id, found := c.hostIDFromMapping(0, c.GidMappings) - if !found { - return -1, fmt.Errorf("User namespaces enabled, but no root group mapping found.") - } - return id, nil - } - // Return default root gid 0 - return 0, nil -} - -// Utility function that gets a host ID for a container ID from user namespace map -// if that ID is present in the map. -func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) { - for _, m := range uMap { - if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) { - hostID := m.HostID + (containerID - m.ContainerID) - return hostID, true - } - } - return -1, false -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go index e45299264c8fb9943219f5d62599295471237886..e4f423c523ff4d042a4b8f6d4d1d47993b429a65 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go @@ -1,9 +1,9 @@ -// +build linux freebsd +// +build linux package configs var ( - // These are devices that are to be both allowed and created. + // DefaultSimpleDevices are devices that are to be both allowed and created. DefaultSimpleDevices = []*Device{ // /dev/null and zero { @@ -107,19 +107,5 @@ var ( Permissions: "rwm", }, }, DefaultSimpleDevices...) - DefaultAutoCreatedDevices = append([]*Device{ - { - // /dev/fuse is created but not allowed. - // This is to allow java to work. Because java - // Insists on there being a /dev/fuse - // https://github.com/docker/docker/issues/514 - // https://github.com/docker/docker/issues/2393 - // - Path: "/dev/fuse", - Type: 'c', - Major: 10, - Minor: 229, - Permissions: "rwm", - }, - }, DefaultSimpleDevices...) + DefaultAutoCreatedDevices = append([]*Device{}, DefaultSimpleDevices...) ) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go new file mode 100644 index 0000000000000000000000000000000000000000..57e9f037d97978724319a3b5e65ad88daa31d9bb --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go @@ -0,0 +1,13 @@ +package configs + +type IntelRdt struct { + // The schema for L3 cache id and capacity bitmask (CBM) + // Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..." + L3CacheSchema string `json:"l3_cache_schema,omitempty"` + + // The schema of memory bandwidth per L3 cache id + // Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..." + // The unit of memory bandwidth is specified in "percentages" by + // default, and in "MBps" if MBA Software Controller is enabled. + MemBwSchema string `json:"memBwSchema,omitempty"` +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go index cc770c916f945728b895baead139f94a4a701f48..670757ddb5f448bbaf126d294d70173f50c1b2f4 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go @@ -1,5 +1,11 @@ package configs +const ( + // EXT_COPYUP is a directive to copy up the contents of a directory when + // a tmpfs is mounted over it. + EXT_COPYUP = 1 << iota +) + type Mount struct { // Source path for the mount. Source string `json:"source"` @@ -22,6 +28,9 @@ type Mount struct { // Relabel source if set, "z" indicates shared, "Z" indicates unshared. Relabel string `json:"relabel"` + // Extensions are additional flags that are specific to runc. + Extensions int `json:"extensions"` + // Optional Command to be run before Source is mounted. PremountCmds []Command `json:"premount_cmds"` diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go similarity index 78% rename from vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go rename to vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go index b9c820d0627d053a724115ccbd74404729c188d8..1bbaef9bd94136276b14d68d0d1136c38964dc6a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_linux.go @@ -1,5 +1,3 @@ -// +build linux freebsd - package configs import ( @@ -9,12 +7,13 @@ import ( ) const ( - NEWNET NamespaceType = "NEWNET" - NEWPID NamespaceType = "NEWPID" - NEWNS NamespaceType = "NEWNS" - NEWUTS NamespaceType = "NEWUTS" - NEWIPC NamespaceType = "NEWIPC" - NEWUSER NamespaceType = "NEWUSER" + NEWNET NamespaceType = "NEWNET" + NEWPID NamespaceType = "NEWPID" + NEWNS NamespaceType = "NEWNS" + NEWUTS NamespaceType = "NEWUTS" + NEWIPC NamespaceType = "NEWIPC" + NEWUSER NamespaceType = "NEWUSER" + NEWCGROUP NamespaceType = "NEWCGROUP" ) var ( @@ -22,8 +21,8 @@ var ( supportedNamespaces = make(map[NamespaceType]bool) ) -// nsToFile converts the namespace type to its filename -func nsToFile(ns NamespaceType) string { +// NsName converts the namespace type to its filename +func NsName(ns NamespaceType) string { switch ns { case NEWNET: return "net" @@ -37,6 +36,8 @@ func nsToFile(ns NamespaceType) string { return "user" case NEWUTS: return "uts" + case NEWCGROUP: + return "cgroup" } return "" } @@ -50,7 +51,7 @@ func IsNamespaceSupported(ns NamespaceType) bool { if ok { return supported } - nsFile := nsToFile(ns) + nsFile := NsName(ns) // if the namespace type is unknown, just return false if nsFile == "" { return false @@ -64,12 +65,13 @@ func IsNamespaceSupported(ns NamespaceType) bool { func NamespaceTypes() []NamespaceType { return []NamespaceType{ + NEWUSER, // Keep user NS always first, don't move it. + NEWIPC, + NEWUTS, NEWNET, NEWPID, NEWNS, - NEWUTS, - NEWIPC, - NEWUSER, + NEWCGROUP, } } @@ -81,10 +83,7 @@ type Namespace struct { } func (n *Namespace) GetPath(pid int) string { - if n.Path != "" { - return n.Path - } - return fmt.Sprintf("/proc/%d/ns/%s", pid, nsToFile(n.Type)) + return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type)) } func (n *Namespaces) Remove(t NamespaceType) bool { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go index c962999efd4bc849ff9b5e5f6b3dc33dbe417608..2dc7adfc9660a5279465d7c7482c1fec8b7fe22c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go @@ -2,23 +2,24 @@ package configs -import "syscall" +import "golang.org/x/sys/unix" func (n *Namespace) Syscall() int { return namespaceInfo[n.Type] } var namespaceInfo = map[NamespaceType]int{ - NEWNET: syscall.CLONE_NEWNET, - NEWNS: syscall.CLONE_NEWNS, - NEWUSER: syscall.CLONE_NEWUSER, - NEWIPC: syscall.CLONE_NEWIPC, - NEWUTS: syscall.CLONE_NEWUTS, - NEWPID: syscall.CLONE_NEWPID, + NEWNET: unix.CLONE_NEWNET, + NEWNS: unix.CLONE_NEWNS, + NEWUSER: unix.CLONE_NEWUSER, + NEWIPC: unix.CLONE_NEWIPC, + NEWUTS: unix.CLONE_NEWUTS, + NEWPID: unix.CLONE_NEWPID, + NEWCGROUP: unix.CLONE_NEWCGROUP, } // CloneFlags parses the container's Namespaces options to set the correct -// flags on clone, unshare. This functions returns flags only for new namespaces. +// flags on clone, unshare. This function returns flags only for new namespaces. func (n *Namespaces) CloneFlags() uintptr { var flag int for _, v := range *n { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go index 1644588dc79d273b69af58fc6419b7c99997333f..5d9a5c81f3fd5c77c97d1a8036838ee717f66cf1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall_unsupported.go @@ -4,12 +4,10 @@ package configs func (n *Namespace) Syscall() int { panic("No namespace syscall support") - return 0 } // CloneFlags parses the container's Namespaces options to set the correct -// flags on clone, unshare. This functions returns flags only for new namespaces. +// flags on clone, unshare. This function returns flags only for new namespaces. func (n *Namespaces) CloneFlags() uintptr { panic("No namespace syscall support") - return uintptr(0) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go index 9a74033ceabe2bed7f5c2ef47c044ac705575a2e..19bf713de3a3a9b9cd04d3107258256dc9d1b48f 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd +// +build !linux package configs diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/config.go deleted file mode 100644 index e155ca1204e5eadc7bd651f6668d530ee4a65d13..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/config.go +++ /dev/null @@ -1,138 +0,0 @@ -package validate - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/opencontainers/runc/libcontainer/configs" -) - -type Validator interface { - Validate(*configs.Config) error -} - -func New() Validator { - return &ConfigValidator{} -} - -type ConfigValidator struct { -} - -func (v *ConfigValidator) Validate(config *configs.Config) error { - if err := v.rootfs(config); err != nil { - return err - } - if err := v.network(config); err != nil { - return err - } - if err := v.hostname(config); err != nil { - return err - } - if err := v.security(config); err != nil { - return err - } - if err := v.usernamespace(config); err != nil { - return err - } - if err := v.sysctl(config); err != nil { - return err - } - return nil -} - -// rootfs validates the the rootfs is an absolute path and is not a symlink -// to the container's root filesystem. -func (v *ConfigValidator) rootfs(config *configs.Config) error { - cleaned, err := filepath.Abs(config.Rootfs) - if err != nil { - return err - } - if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil { - return err - } - if config.Rootfs != cleaned { - return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs) - } - return nil -} - -func (v *ConfigValidator) network(config *configs.Config) error { - if !config.Namespaces.Contains(configs.NEWNET) { - if len(config.Networks) > 0 || len(config.Routes) > 0 { - return fmt.Errorf("unable to apply network settings without a private NET namespace") - } - } - return nil -} - -func (v *ConfigValidator) hostname(config *configs.Config) error { - if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) { - return fmt.Errorf("unable to set hostname without a private UTS namespace") - } - return nil -} - -func (v *ConfigValidator) security(config *configs.Config) error { - // restrict sys without mount namespace - if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) && - !config.Namespaces.Contains(configs.NEWNS) { - return fmt.Errorf("unable to restrict sys entries without a private MNT namespace") - } - return nil -} - -func (v *ConfigValidator) usernamespace(config *configs.Config) error { - if config.Namespaces.Contains(configs.NEWUSER) { - if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { - return fmt.Errorf("USER namespaces aren't enabled in the kernel") - } - } else { - if config.UidMappings != nil || config.GidMappings != nil { - return fmt.Errorf("User namespace mappings specified, but USER namespace isn't enabled in the config") - } - } - return nil -} - -// sysctl validates that the specified sysctl keys are valid or not. -// /proc/sys isn't completely namespaced and depending on which namespaces -// are specified, a subset of sysctls are permitted. -func (v *ConfigValidator) sysctl(config *configs.Config) error { - validSysctlPrefixes := []string{} - validSysctlMap := make(map[string]bool) - if config.Namespaces.Contains(configs.NEWNET) { - validSysctlPrefixes = append(validSysctlPrefixes, "net.") - } - if config.Namespaces.Contains(configs.NEWIPC) { - validSysctlPrefixes = append(validSysctlPrefixes, "fs.mqueue.") - validSysctlMap = map[string]bool{ - "kernel.msgmax": true, - "kernel.msgmnb": true, - "kernel.msgmni": true, - "kernel.sem": true, - "kernel.shmall": true, - "kernel.shmmax": true, - "kernel.shmmni": true, - "kernel.shm_rmid_forced": true, - } - } - for s := range config.Sysctl { - if validSysctlMap[s] { - continue - } - valid := false - for _, vp := range validSysctlPrefixes { - if strings.HasPrefix(s, vp) { - valid = true - break - } - } - if !valid { - return fmt.Errorf("sysctl %q is not permitted in the config", s) - } - } - - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go new file mode 100644 index 0000000000000000000000000000000000000000..393d9e81ee92b1b629f3fd7ba7a6dce63cf21dd8 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go @@ -0,0 +1,89 @@ +package validate + +import ( + "fmt" + "strings" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +// rootlessEUID makes sure that the config can be applied when runc +// is being executed as a non-root user (euid != 0) in the current user namespace. +func (v *ConfigValidator) rootlessEUID(config *configs.Config) error { + if err := rootlessEUIDMappings(config); err != nil { + return err + } + if err := rootlessEUIDMount(config); err != nil { + return err + } + + // XXX: We currently can't verify the user config at all, because + // configs.Config doesn't store the user-related configs. So this + // has to be verified by setupUser() in init_linux.go. + + return nil +} + +func hasIDMapping(id int, mappings []configs.IDMap) bool { + for _, m := range mappings { + if id >= m.ContainerID && id < m.ContainerID+m.Size { + return true + } + } + return false +} + +func rootlessEUIDMappings(config *configs.Config) error { + if !config.Namespaces.Contains(configs.NEWUSER) { + return fmt.Errorf("rootless container requires user namespaces") + } + + if len(config.UidMappings) == 0 { + return fmt.Errorf("rootless containers requires at least one UID mapping") + } + if len(config.GidMappings) == 0 { + return fmt.Errorf("rootless containers requires at least one GID mapping") + } + return nil +} + +// mount verifies that the user isn't trying to set up any mounts they don't have +// the rights to do. In addition, it makes sure that no mount has a `uid=` or +// `gid=` option that doesn't resolve to root. +func rootlessEUIDMount(config *configs.Config) error { + // XXX: We could whitelist allowed devices at this point, but I'm not + // convinced that's a good idea. The kernel is the best arbiter of + // access control. + + for _, mount := range config.Mounts { + // Check that the options list doesn't contain any uid= or gid= entries + // that don't resolve to root. + for _, opt := range strings.Split(mount.Data, ",") { + if strings.HasPrefix(opt, "uid=") { + var uid int + n, err := fmt.Sscanf(opt, "uid=%d", &uid) + if n != 1 || err != nil { + // Ignore unknown mount options. + continue + } + if !hasIDMapping(uid, config.UidMappings) { + return fmt.Errorf("cannot specify uid= mount options for unmapped uid in rootless containers") + } + } + + if strings.HasPrefix(opt, "gid=") { + var gid int + n, err := fmt.Sscanf(opt, "gid=%d", &gid) + if n != 1 || err != nil { + // Ignore unknown mount options. + continue + } + if !hasIDMapping(gid, config.GidMappings) { + return fmt.Errorf("cannot specify gid= mount options for unmapped gid in rootless containers") + } + } + } + } + + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless_test.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless_test.go new file mode 100644 index 0000000000000000000000000000000000000000..59d15575dd7c48e4695e3354836107a72d29819a --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless_test.go @@ -0,0 +1,155 @@ +package validate + +import ( + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +func rootlessEUIDConfig() *configs.Config { + return &configs.Config{ + Rootfs: "/var", + RootlessEUID: true, + RootlessCgroups: true, + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWUSER}, + }, + ), + UidMappings: []configs.IDMap{ + { + HostID: 1337, + ContainerID: 0, + Size: 1, + }, + }, + GidMappings: []configs.IDMap{ + { + HostID: 7331, + ContainerID: 0, + Size: 1, + }, + }, + } +} + +func TestValidateRootlessEUID(t *testing.T) { + validator := New() + + config := rootlessEUIDConfig() + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur: %+v", err) + } +} + +/* rootlessEUIDMappings */ + +func TestValidateRootlessEUIDUserns(t *testing.T) { + validator := New() + + config := rootlessEUIDConfig() + config.Namespaces = nil + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur if user namespaces not set") + } +} + +func TestValidateRootlessEUIDMappingUid(t *testing.T) { + validator := New() + + config := rootlessEUIDConfig() + config.UidMappings = nil + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur if no uid mappings provided") + } +} + +func TestValidateNonZeroEUIDMappingGid(t *testing.T) { + validator := New() + + config := rootlessEUIDConfig() + config.GidMappings = nil + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur if no gid mappings provided") + } +} + +/* rootlessEUIDMount() */ + +func TestValidateRootlessEUIDMountUid(t *testing.T) { + config := rootlessEUIDConfig() + validator := New() + + config.Mounts = []*configs.Mount{ + { + Source: "devpts", + Destination: "/dev/pts", + Device: "devpts", + }, + } + + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when uid= not set in mount options: %+v", err) + } + + config.Mounts[0].Data = "uid=5" + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur when setting uid=5 in mount options") + } + + config.Mounts[0].Data = "uid=0" + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when setting uid=0 in mount options: %+v", err) + } + + config.Mounts[0].Data = "uid=2" + config.UidMappings[0].Size = 10 + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when setting uid=2 in mount options and UidMapping[0].size is 10") + } + + config.Mounts[0].Data = "uid=20" + config.UidMappings[0].Size = 10 + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur when setting uid=20 in mount options and UidMapping[0].size is 10") + } +} + +func TestValidateRootlessEUIDMountGid(t *testing.T) { + config := rootlessEUIDConfig() + validator := New() + + config.Mounts = []*configs.Mount{ + { + Source: "devpts", + Destination: "/dev/pts", + Device: "devpts", + }, + } + + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when gid= not set in mount options: %+v", err) + } + + config.Mounts[0].Data = "gid=5" + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur when setting gid=5 in mount options") + } + + config.Mounts[0].Data = "gid=0" + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when setting gid=0 in mount options: %+v", err) + } + + config.Mounts[0].Data = "gid=5" + config.GidMappings[0].Size = 10 + if err := validator.Validate(config); err != nil { + t.Errorf("Expected error to not occur when setting gid=5 in mount options and GidMapping[0].size is 10") + } + + config.Mounts[0].Data = "gid=11" + config.GidMappings[0].Size = 10 + if err := validator.Validate(config); err == nil { + t.Errorf("Expected error to occur when setting gid=11 in mount options and GidMapping[0].size is 10") + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go new file mode 100644 index 0000000000000000000000000000000000000000..3b42f30107a0da14f1cc35a9cd22a0c255bca9b7 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go @@ -0,0 +1,245 @@ +package validate + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + selinux "github.com/opencontainers/selinux/go-selinux" +) + +type Validator interface { + Validate(*configs.Config) error +} + +func New() Validator { + return &ConfigValidator{} +} + +type ConfigValidator struct { +} + +func (v *ConfigValidator) Validate(config *configs.Config) error { + if err := v.rootfs(config); err != nil { + return err + } + if err := v.network(config); err != nil { + return err + } + if err := v.hostname(config); err != nil { + return err + } + if err := v.security(config); err != nil { + return err + } + if err := v.usernamespace(config); err != nil { + return err + } + if err := v.cgroupnamespace(config); err != nil { + return err + } + if err := v.sysctl(config); err != nil { + return err + } + if err := v.intelrdt(config); err != nil { + return err + } + if config.RootlessEUID { + if err := v.rootlessEUID(config); err != nil { + return err + } + } + return nil +} + +// rootfs validates if the rootfs is an absolute path and is not a symlink +// to the container's root filesystem. +func (v *ConfigValidator) rootfs(config *configs.Config) error { + if _, err := os.Stat(config.Rootfs); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs) + } + return err + } + cleaned, err := filepath.Abs(config.Rootfs) + if err != nil { + return err + } + if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil { + return err + } + if filepath.Clean(config.Rootfs) != cleaned { + return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs) + } + return nil +} + +func (v *ConfigValidator) network(config *configs.Config) error { + if !config.Namespaces.Contains(configs.NEWNET) { + if len(config.Networks) > 0 || len(config.Routes) > 0 { + return fmt.Errorf("unable to apply network settings without a private NET namespace") + } + } + return nil +} + +func (v *ConfigValidator) hostname(config *configs.Config) error { + if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) { + return fmt.Errorf("unable to set hostname without a private UTS namespace") + } + return nil +} + +func (v *ConfigValidator) security(config *configs.Config) error { + // restrict sys without mount namespace + if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) && + !config.Namespaces.Contains(configs.NEWNS) { + return fmt.Errorf("unable to restrict sys entries without a private MNT namespace") + } + if config.ProcessLabel != "" && !selinux.GetEnabled() { + return fmt.Errorf("selinux label is specified in config, but selinux is disabled or not supported") + } + + return nil +} + +func (v *ConfigValidator) usernamespace(config *configs.Config) error { + if config.Namespaces.Contains(configs.NEWUSER) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + return fmt.Errorf("USER namespaces aren't enabled in the kernel") + } + } else { + if config.UidMappings != nil || config.GidMappings != nil { + return fmt.Errorf("User namespace mappings specified, but USER namespace isn't enabled in the config") + } + } + return nil +} + +func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error { + if config.Namespaces.Contains(configs.NEWCGROUP) { + if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + return fmt.Errorf("cgroup namespaces aren't enabled in the kernel") + } + } + return nil +} + +// sysctl validates that the specified sysctl keys are valid or not. +// /proc/sys isn't completely namespaced and depending on which namespaces +// are specified, a subset of sysctls are permitted. +func (v *ConfigValidator) sysctl(config *configs.Config) error { + validSysctlMap := map[string]bool{ + "kernel.msgmax": true, + "kernel.msgmnb": true, + "kernel.msgmni": true, + "kernel.sem": true, + "kernel.shmall": true, + "kernel.shmmax": true, + "kernel.shmmni": true, + "kernel.shm_rmid_forced": true, + } + + for s := range config.Sysctl { + if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") { + if config.Namespaces.Contains(configs.NEWIPC) { + continue + } else { + return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s) + } + } + if strings.HasPrefix(s, "net.") { + if config.Namespaces.Contains(configs.NEWNET) { + if path := config.Namespaces.PathOf(configs.NEWNET); path != "" { + if err := checkHostNs(s, path); err != nil { + return err + } + } + continue + } else { + return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", s) + } + } + if config.Namespaces.Contains(configs.NEWUTS) { + switch s { + case "kernel.domainname": + // This is namespaced and there's no explicit OCI field for it. + continue + case "kernel.hostname": + // This is namespaced but there's a conflicting (dedicated) OCI field for it. + return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname") + } + } + return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s) + } + + return nil +} + +func (v *ConfigValidator) intelrdt(config *configs.Config) error { + if config.IntelRdt != nil { + if !intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() { + return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not supported or enabled") + } + + if !intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema != "" { + return fmt.Errorf("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled") + } + if !intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema != "" { + return fmt.Errorf("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled") + } + + if intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema == "" { + return fmt.Errorf("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty") + } + if intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema == "" { + return fmt.Errorf("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty") + } + } + + return nil +} + +func isSymbolicLink(path string) (bool, error) { + fi, err := os.Lstat(path) + if err != nil { + return false, err + } + + return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil +} + +// checkHostNs checks whether network sysctl is used in host namespace. +func checkHostNs(sysctlConfig string, path string) error { + var currentProcessNetns = "/proc/self/ns/net" + // readlink on the current processes network namespace + destOfCurrentProcess, err := os.Readlink(currentProcessNetns) + if err != nil { + return fmt.Errorf("read soft link %q error", currentProcessNetns) + } + + // First check if the provided path is a symbolic link + symLink, err := isSymbolicLink(path) + if err != nil { + return fmt.Errorf("could not check that %q is a symlink: %v", path, err) + } + + if symLink == false { + // The provided namespace is not a symbolic link, + // it is not the host namespace. + return nil + } + + // readlink on the path provided in the struct + destOfContainer, err := os.Readlink(path) + if err != nil { + return fmt.Errorf("read soft link %q error", path) + } + if destOfContainer == destOfCurrentProcess { + return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", sysctlConfig) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator_test.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f6826fb3efc11316e83cfaf0983ed2b376cc18c4 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator_test.go @@ -0,0 +1,267 @@ +package validate_test + +import ( + "os" + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/configs/validate" +) + +func TestValidate(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("Expected error to not occur: %+v", err) + } +} + +func TestValidateWithInvalidRootfs(t *testing.T) { + dir := "rootfs" + os.Symlink("/var", dir) + defer os.Remove(dir) + + config := &configs.Config{ + Rootfs: dir, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateNetworkWithoutNETNamespace(t *testing.T) { + network := &configs.Network{Type: "loopback"} + config := &configs.Config{ + Rootfs: "/var", + Namespaces: []configs.Namespace{}, + Networks: []*configs.Network{network}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateNetworkRoutesWithoutNETNamespace(t *testing.T) { + route := &configs.Route{Gateway: "255.255.255.0"} + config := &configs.Config{ + Rootfs: "/var", + Namespaces: []configs.Namespace{}, + Routes: []*configs.Route{route}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateHostname(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + Hostname: "runc", + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWUTS}, + }, + ), + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("Expected error to not occur: %+v", err) + } +} + +func TestValidateHostnameWithoutUTSNamespace(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + Hostname: "runc", + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateSecurityWithMaskPaths(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + MaskPaths: []string{"/proc/kcore"}, + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWNS}, + }, + ), + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("Expected error to not occur: %+v", err) + } +} + +func TestValidateSecurityWithROPaths(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + ReadonlyPaths: []string{"/proc/sys"}, + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWNS}, + }, + ), + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("Expected error to not occur: %+v", err) + } +} + +func TestValidateSecurityWithoutNEWNS(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + MaskPaths: []string{"/proc/kcore"}, + ReadonlyPaths: []string{"/proc/sys"}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateUsernamespace(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + t.Skip("userns is unsupported") + } + config := &configs.Config{ + Rootfs: "/var", + Namespaces: configs.Namespaces( + []configs.Namespace{ + {Type: configs.NEWUSER}, + }, + ), + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("expected error to not occur %+v", err) + } +} + +func TestValidateUsernamespaceWithoutUserNS(t *testing.T) { + uidMap := configs.IDMap{ContainerID: 123} + config := &configs.Config{ + Rootfs: "/var", + UidMappings: []configs.IDMap{uidMap}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateSysctl(t *testing.T) { + sysctl := map[string]string{ + "fs.mqueue.ctl": "ctl", + "net.ctl": "ctl", + "kernel.ctl": "ctl", + } + + for k, v := range sysctl { + config := &configs.Config{ + Rootfs: "/var", + Sysctl: map[string]string{k: v}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } + } +} + +func TestValidateValidSysctl(t *testing.T) { + sysctl := map[string]string{ + "fs.mqueue.ctl": "ctl", + "net.ctl": "ctl", + "kernel.msgmax": "ctl", + } + + for k, v := range sysctl { + config := &configs.Config{ + Rootfs: "/var", + Sysctl: map[string]string{k: v}, + Namespaces: []configs.Namespace{ + { + Type: configs.NEWNET, + }, + { + Type: configs.NEWIPC, + }, + }, + } + + validator := validate.New() + err := validator.Validate(config) + if err != nil { + t.Errorf("Expected error to not occur with {%s=%s} but got: %q", k, v, err) + } + } +} + +func TestValidateSysctlWithSameNs(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + Sysctl: map[string]string{"net.ctl": "ctl"}, + Namespaces: configs.Namespaces( + []configs.Namespace{ + { + Type: configs.NEWNET, + Path: "/proc/self/ns/net", + }, + }, + ), + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} + +func TestValidateSysctlWithoutNETNamespace(t *testing.T) { + config := &configs.Config{ + Rootfs: "/var", + Sysctl: map[string]string{"net.ctl": "ctl"}, + Namespaces: []configs.Namespace{}, + } + + validator := validate.New() + err := validator.Validate(config) + if err == nil { + t.Error("Expected error to occur but it was nil") + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console.go b/vendor/github.com/opencontainers/runc/libcontainer/console.go deleted file mode 100644 index 042a2a2e481b45d603432ba21682ea4a42f8bd32..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/console.go +++ /dev/null @@ -1,15 +0,0 @@ -package libcontainer - -import "io" - -// Console represents a pseudo TTY. -type Console interface { - io.ReadWriter - io.Closer - - // Path returns the filesystem path to the slave side of the pty. - Path() string - - // Fd returns the fd for the master of the pty. - Fd() uintptr -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console_freebsd.go b/vendor/github.com/opencontainers/runc/libcontainer/console_freebsd.go deleted file mode 100644 index 3c89eda0799297996e6455413849540a966b8087..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/console_freebsd.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build freebsd - -package libcontainer - -import ( - "errors" -) - -// NewConsole returns an initalized console that can be used within a container by copying bytes -// from the master side to the slave that is attached as the tty for the container's init process. -func NewConsole(uid, gid int) (Console, error) { - return nil, errors.New("libcontainer console is not supported on FreeBSD") -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go index 7af771b65e3d6ef95d029c30aec3bd3ff5a84f2b..9997e93ed4f3fbc1c5a90c3df0a7d7233377e94b 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go @@ -1,145 +1,41 @@ package libcontainer import ( - "fmt" "os" - "path/filepath" - "syscall" - "unsafe" - "github.com/opencontainers/runc/libcontainer/label" + "golang.org/x/sys/unix" ) -// NewConsole returns an initalized console that can be used within a container by copying bytes -// from the master side to the slave that is attached as the tty for the container's init process. -func NewConsole(uid, gid int) (Console, error) { - master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0) - if err != nil { - return nil, err - } - console, err := ptsname(master) - if err != nil { - return nil, err - } - if err := unlockpt(master); err != nil { - return nil, err - } - if err := os.Chmod(console, 0600); err != nil { - return nil, err - } - if err := os.Chown(console, uid, gid); err != nil { - return nil, err - } - return &linuxConsole{ - slavePath: console, - master: master, - }, nil -} - -// newConsoleFromPath is an internal function returning an initialized console for use inside -// a container's MNT namespace. -func newConsoleFromPath(slavePath string) *linuxConsole { - return &linuxConsole{ - slavePath: slavePath, - } -} - -// linuxConsole is a linux psuedo TTY for use within a container. -type linuxConsole struct { - master *os.File - slavePath string -} - -func (c *linuxConsole) Fd() uintptr { - return c.master.Fd() -} - -func (c *linuxConsole) Path() string { - return c.slavePath -} - -func (c *linuxConsole) Read(b []byte) (int, error) { - return c.master.Read(b) -} - -func (c *linuxConsole) Write(b []byte) (int, error) { - return c.master.Write(b) -} - -func (c *linuxConsole) Close() error { - if m := c.master; m != nil { - return m.Close() - } - return nil -} - // mount initializes the console inside the rootfs mounting with the specified mount label // and applying the correct ownership of the console. -func (c *linuxConsole) mount(rootfs, mountLabel string) error { - oldMask := syscall.Umask(0000) - defer syscall.Umask(oldMask) - if err := label.SetFileLabel(c.slavePath, mountLabel); err != nil { - return err - } - dest := filepath.Join(rootfs, "/dev/console") - f, err := os.Create(dest) +func mountConsole(slavePath string) error { + oldMask := unix.Umask(0000) + defer unix.Umask(oldMask) + f, err := os.Create("/dev/console") if err != nil && !os.IsExist(err) { return err } if f != nil { f.Close() } - return syscall.Mount(c.slavePath, dest, "bind", syscall.MS_BIND, "") + return unix.Mount(slavePath, "/dev/console", "bind", unix.MS_BIND, "") } // dupStdio opens the slavePath for the console and dups the fds to the current // processes stdio, fd 0,1,2. -func (c *linuxConsole) dupStdio() error { - slave, err := c.open(syscall.O_RDWR) +func dupStdio(slavePath string) error { + fd, err := unix.Open(slavePath, unix.O_RDWR, 0) if err != nil { - return err + return &os.PathError{ + Op: "open", + Path: slavePath, + Err: err, + } } - fd := int(slave.Fd()) for _, i := range []int{0, 1, 2} { - if err := syscall.Dup3(fd, i, 0); err != nil { + if err := unix.Dup3(fd, i, 0); err != nil { return err } } return nil } - -// open is a clone of os.OpenFile without the O_CLOEXEC used to open the pty slave. -func (c *linuxConsole) open(flag int) (*os.File, error) { - r, e := syscall.Open(c.slavePath, flag, 0) - if e != nil { - return nil, &os.PathError{ - Op: "open", - Path: c.slavePath, - Err: e, - } - } - return os.NewFile(uintptr(r), c.slavePath), nil -} - -func ioctl(fd uintptr, flag, data uintptr) error { - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 { - return err - } - return nil -} - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - var u int32 - return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - var n int32 - if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", n), nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/console_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/console_windows.go deleted file mode 100644 index a68c02f66b45f1d8a26b1a588855259e7dd5f441..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/console_windows.go +++ /dev/null @@ -1,30 +0,0 @@ -package libcontainer - -// NewConsole returns an initalized console that can be used within a container -func NewConsole(uid, gid int) (Console, error) { - return &windowsConsole{}, nil -} - -// windowsConsole is a Windows psuedo TTY for use within a container. -type windowsConsole struct { -} - -func (c *windowsConsole) Fd() uintptr { - return 0 -} - -func (c *windowsConsole) Path() string { - return "" -} - -func (c *windowsConsole) Read(b []byte) (int, error) { - return 0, nil -} - -func (c *windowsConsole) Write(b []byte) (int, error) { - return 0, nil -} - -func (c *windowsConsole) Close() error { - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container.go b/vendor/github.com/opencontainers/runc/libcontainer/container.go index 32daa97675a9935b768b9f19c055d5dc3848d651..ba7541c5fd68f3c860c03cffa8f1d9d997aaf6d3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container.go @@ -1,4 +1,4 @@ -// Libcontainer provides a native Go implementation for creating containers +// Package libcontainer provides a native Go implementation for creating containers // with namespaces, cgroups, capabilities, and filesystem access controls. // It allows you to manage the lifecycle of the container performing additional operations // after the container is created. @@ -9,26 +9,23 @@ import ( "time" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" ) -// The status of a container. +// Status is the status of a container. type Status int const ( - // The container exists but has not been run yet + // Created is the status that denotes the container exists but has not been run yet. Created Status = iota - - // The container exists and is running. + // Running is the status that denotes the container exists and is running. Running - - // The container exists, it is in the process of being paused. + // Pausing is the status that denotes the container exists, it is in the process of being paused. Pausing - - // The container exists, but all its processes are paused. + // Paused is the status that denotes the container exists, but all its processes are paused. Paused - - // The container does not exist. - Destroyed + // Stopped is the status that denotes the container does not have a created or running process. + Stopped ) func (s Status) String() string { @@ -41,8 +38,8 @@ func (s Status) String() string { return "pausing" case Paused: return "paused" - case Destroyed: - return "destroyed" + case Stopped: + return "stopped" default: return "unknown" } @@ -58,7 +55,7 @@ type BaseState struct { InitProcessPid int `json:"init_process_pid"` // InitProcessStartTime is the init process start time in clock cycles since boot time. - InitProcessStartTime string `json:"init_process_start"` + InitProcessStartTime uint64 `json:"init_process_start"` // Created is the unix timestamp for the creation time of the container in UTC Created time.Time `json:"created"` @@ -67,7 +64,7 @@ type BaseState struct { Config configs.Config `json:"config"` } -// A libcontainer container object. +// BaseContainer is a libcontainer container object. // // Each container is thread-safe within the same process. Since a container can // be destroyed by a separate process, any function may return that the container @@ -79,23 +76,29 @@ type BaseContainer interface { // Returns the current status of the container. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, // Systemerror - System error. Status() (Status, error) // State returns the current container's state information. // // errors: - // Systemerror - System error. + // SystemError - System error. State() (*State, error) + // OCIState returns the current container's state information. + // + // errors: + // SystemError - System error. + OCIState() (*specs.State, error) + // Returns the current config of the container. Config() configs.Config // Returns the PIDs inside this container. The PIDs are in the namespace of the calling process. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, // Systemerror - System error. // // Some of the returned PIDs may no longer refer to processes in the Container, unless @@ -105,7 +108,7 @@ type BaseContainer interface { // Returns statistics for the container. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, // Systemerror - System error. Stats() (*Stats, error) @@ -114,31 +117,57 @@ type BaseContainer interface { // We can use this to change resources when containers are running. // // errors: - // Systemerror - System error. + // SystemError - System error. Set(config configs.Config) error // Start a process inside the container. Returns error if process fails to // start. You can track process lifecycle with passed Process structure. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, // ConfigInvalid - config is invalid, // ContainerPaused - Container is paused, - // Systemerror - System error. + // SystemError - System error. Start(process *Process) (err error) - // Destroys the container after killing all running processes. + // Run immediately starts the process inside the container. Returns error if process + // fails to start. It does not block waiting for the exec fifo after start returns but + // opens the fifo after start returns. + // + // errors: + // ContainerNotExists - Container no longer exists, + // ConfigInvalid - config is invalid, + // ContainerPaused - Container is paused, + // SystemError - System error. + Run(process *Process) (err error) + + // Destroys the container, if its in a valid state, after killing any + // remaining running processes. // // Any event registrations are removed before the container is destroyed. // No error is returned if the container is already destroyed. // + // Running containers must first be stopped using Signal(..). + // Paused containers must first be resumed using Resume(..). + // // errors: - // Systemerror - System error. + // ContainerNotStopped - Container is still running, + // ContainerPaused - Container is paused, + // SystemError - System error. Destroy() error // Signal sends the provided signal code to the container's initial process. // + // If all is specified the signal is sent to all processes in the container + // including the initial process. + // // errors: - // Systemerror - System error. - Signal(s os.Signal) error + // SystemError - System error. + Signal(s os.Signal, all bool) error + + // Exec signals the container to exec the users process at the end of the init. + // + // errors: + // SystemError - System error. + Exec() error } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go index a03debbb2da3ebf342576436e983c64a19188ea1..ef443f6fc16f6c38529a2afc8a66881366c8b166 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -5,43 +5,53 @@ package libcontainer import ( "bytes" "encoding/json" + "errors" "fmt" "io" "io/ioutil" + "net" "os" "os/exec" "path/filepath" "reflect" "strings" "sync" - "syscall" + "syscall" // only for SysProcAttr and Signal "time" - "github.com/sirupsen/logrus" - "github.com/golang/protobuf/proto" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/criurpc" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/utils" - "github.com/syndtr/gocapability/capability" + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/golang/protobuf/proto" + "github.com/sirupsen/logrus" "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" ) const stdioFdCount = 3 type linuxContainer struct { - id string - root string - config *configs.Config - cgroupManager cgroups.Manager - initPath string - initArgs []string - initProcess parentProcess - criuPath string - m sync.Mutex - criuVersion int - state containerState - created time.Time + id string + root string + config *configs.Config + cgroupManager cgroups.Manager + intelRdtManager intelrdt.Manager + initPath string + initArgs []string + initProcess parentProcess + initProcessStartTime uint64 + criuPath string + newuidmapPath string + newgidmapPath string + m sync.Mutex + criuVersion int + state containerState + created time.Time } // State represents a running container's state @@ -50,6 +60,10 @@ type State struct { // Platform specific fields below here + // Specified if the container was started under the rootless mode. + // Set to true if BaseState.Config.RootlessEUID && BaseState.Config.RootlessCgroups + Rootless bool `json:"rootless"` + // Path to all the cgroups setup for a container. Key is cgroup subsystem name // with the value as the path. CgroupPaths map[string]string `json:"cgroup_paths"` @@ -60,9 +74,12 @@ type State struct { // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore ExternalDescriptors []string `json:"external_descriptors,omitempty"` + + // Intel RDT "resource control" filesystem path + IntelRdtPath string `json:"intel_rdt_path"` } -// A libcontainer container object. +// Container is a libcontainer container object. // // Each container is thread-safe within the same process. Since a container can // be destroyed by a separate process, any function may return that the container @@ -78,19 +95,20 @@ type Container interface { // Systemerror - System error. Checkpoint(criuOpts *CriuOpts) error - // Restore restores the checkpointed container to a running state using the criu(8) utiity. + // Restore restores the checkpointed container to a running state using the criu(8) utility. // // errors: // Systemerror - System error. Restore(process *Process, criuOpts *CriuOpts) error - // If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses + // If the Container state is RUNNING or CREATED, sets the Container state to PAUSING and pauses // the execution of any user processes. Asynchronously, when the container finished being paused the // state is changed to PAUSED. // If the Container state is PAUSED, do nothing. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, + // ContainerNotRunning - Container not running or created, // Systemerror - System error. Pause() error @@ -99,7 +117,8 @@ type Container interface { // If the Container state is RUNNING, do nothing. // // errors: - // ContainerDestroyed - Container no longer exists, + // ContainerNotExists - Container no longer exists, + // ContainerNotPaused - Container is not paused, // Systemerror - System error. Resume() error @@ -138,10 +157,16 @@ func (c *linuxContainer) State() (*State, error) { return c.currentState() } +func (c *linuxContainer) OCIState() (*specs.State, error) { + c.m.Lock() + defer c.m.Unlock() + return c.currentOCIState() +} + func (c *linuxContainer) Processes() ([]int, error) { pids, err := c.cgroupManager.GetAllPids() if err != nil { - return nil, newSystemError(err) + return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups") } return pids, nil } @@ -152,14 +177,19 @@ func (c *linuxContainer) Stats() (*Stats, error) { stats = &Stats{} ) if stats.CgroupStats, err = c.cgroupManager.GetStats(); err != nil { - return stats, newSystemError(err) + return stats, newSystemErrorWithCause(err, "getting container stats from cgroups") + } + if c.intelRdtManager != nil { + if stats.IntelRdtStats, err = c.intelRdtManager.GetStats(); err != nil { + return stats, newSystemErrorWithCause(err, "getting container's Intel RDT stats") + } } for _, iface := range c.config.Networks { switch iface.Type { case "veth": istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) if err != nil { - return stats, newSystemError(err) + return stats, newSystemErrorWithCausef(err, "getting network stats for interface %q", iface.HostInterfaceName) } stats.Interfaces = append(stats.Interfaces, istats) } @@ -170,52 +200,172 @@ func (c *linuxContainer) Stats() (*Stats, error) { func (c *linuxContainer) Set(config configs.Config) error { c.m.Lock() defer c.m.Unlock() + status, err := c.currentStatus() + if err != nil { + return err + } + if status == Stopped { + return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning) + } + if err := c.cgroupManager.Set(&config); err != nil { + // Set configs back + if err2 := c.cgroupManager.Set(c.config); err2 != nil { + logrus.Warnf("Setting back cgroup configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2) + } + return err + } + if c.intelRdtManager != nil { + if err := c.intelRdtManager.Set(&config); err != nil { + // Set configs back + if err2 := c.intelRdtManager.Set(c.config); err2 != nil { + logrus.Warnf("Setting back intelrdt configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2) + } + return err + } + } + // After config setting succeed, update config and states c.config = &config - return c.cgroupManager.Set(c.config) + _, err = c.updateState(nil) + return err } func (c *linuxContainer) Start(process *Process) error { c.m.Lock() defer c.m.Unlock() - status, err := c.currentStatus() + if process.Init { + if err := c.createExecFifo(); err != nil { + return err + } + } + if err := c.start(process); err != nil { + if process.Init { + c.deleteExecFifo() + } + return err + } + return nil +} + +func (c *linuxContainer) Run(process *Process) error { + if err := c.Start(process); err != nil { + return err + } + if process.Init { + return c.exec() + } + return nil +} + +func (c *linuxContainer) Exec() error { + c.m.Lock() + defer c.m.Unlock() + return c.exec() +} + +func (c *linuxContainer) exec() error { + path := filepath.Join(c.root, execFifoFilename) + + fifoOpen := make(chan struct{}) + select { + case <-awaitProcessExit(c.initProcess.pid(), fifoOpen): + return errors.New("container process is already dead") + case result := <-awaitFifoOpen(path): + close(fifoOpen) + if result.err != nil { + return result.err + } + f := result.file + defer f.Close() + if err := readFromExecFifo(f); err != nil { + return err + } + return os.Remove(path) + } +} + +func readFromExecFifo(execFifo io.Reader) error { + data, err := ioutil.ReadAll(execFifo) if err != nil { return err } - doInit := status == Destroyed - parent, err := c.newParentProcess(process, doInit) + if len(data) <= 0 { + return fmt.Errorf("cannot start an already running container") + } + return nil +} + +func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} { + isDead := make(chan struct{}) + go func() { + for { + select { + case <-exit: + return + case <-time.After(time.Millisecond * 100): + stat, err := system.Stat(pid) + if err != nil || stat.State == system.Zombie { + close(isDead) + return + } + } + } + }() + return isDead +} + +func awaitFifoOpen(path string) <-chan openResult { + fifoOpened := make(chan openResult) + go func() { + f, err := os.OpenFile(path, os.O_RDONLY, 0) + if err != nil { + fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} + return + } + fifoOpened <- openResult{file: f} + }() + return fifoOpened +} + +type openResult struct { + file *os.File + err error +} + +func (c *linuxContainer) start(process *Process) error { + parent, err := c.newParentProcess(process) if err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "creating new parent process") } if err := parent.start(); err != nil { // terminate the process to ensure that it properly is reaped. - if err := parent.terminate(); err != nil { + if err := ignoreTerminateErrors(parent.terminate()); err != nil { logrus.Warn(err) } - return newSystemError(err) + return newSystemErrorWithCause(err, "starting container process") } // generate a timestamp indicating when the container was started c.created = time.Now().UTC() - - c.state = &runningState{ - c: c, - } - if doInit { - if err := c.updateState(parent); err != nil { + if process.Init { + c.state = &createdState{ + c: c, + } + state, err := c.updateState(parent) + if err != nil { return err } + c.initProcessStartTime = state.InitProcessStartTime + if c.config.Hooks != nil { - s := configs.HookState{ - Version: c.config.Version, - ID: c.id, - Pid: parent.pid(), - Root: c.config.Rootfs, + s, err := c.currentOCIState() + if err != nil { + return err } - for _, hook := range c.config.Hooks.Poststart { + for i, hook := range c.config.Hooks.Poststart { if err := hook.Run(s); err != nil { - if err := parent.terminate(); err != nil { + if err := ignoreTerminateErrors(parent.terminate()); err != nil { logrus.Warn(err) } - return newSystemError(err) + return newSystemErrorWithCausef(err, "running poststart hook %d", i) } } } @@ -223,33 +373,96 @@ func (c *linuxContainer) Start(process *Process) error { return nil } -func (c *linuxContainer) Signal(s os.Signal) error { - if err := c.initProcess.signal(s); err != nil { - return newSystemError(err) +func (c *linuxContainer) Signal(s os.Signal, all bool) error { + if all { + return signalAllProcesses(c.cgroupManager, s) } + status, err := c.currentStatus() + if err != nil { + return err + } + // to avoid a PID reuse attack + if status == Running || status == Created || status == Paused { + if err := c.initProcess.signal(s); err != nil { + return newSystemErrorWithCause(err, "signaling init process") + } + return nil + } + return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning) +} + +func (c *linuxContainer) createExecFifo() error { + rootuid, err := c.Config().HostRootUID() + if err != nil { + return err + } + rootgid, err := c.Config().HostRootGID() + if err != nil { + return err + } + + fifoName := filepath.Join(c.root, execFifoFilename) + if _, err := os.Stat(fifoName); err == nil { + return fmt.Errorf("exec fifo %s already exists", fifoName) + } + oldMask := unix.Umask(0000) + if err := unix.Mkfifo(fifoName, 0622); err != nil { + unix.Umask(oldMask) + return err + } + unix.Umask(oldMask) + return os.Chown(fifoName, rootuid, rootgid) +} + +func (c *linuxContainer) deleteExecFifo() { + fifoName := filepath.Join(c.root, execFifoFilename) + os.Remove(fifoName) +} + +// includeExecFifo opens the container's execfifo as a pathfd, so that the +// container cannot access the statedir (and the FIFO itself remains +// un-opened). It then adds the FifoFd to the given exec.Cmd as an inherited +// fd, with _LIBCONTAINER_FIFOFD set to its fd number. +func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error { + fifoName := filepath.Join(c.root, execFifoFilename) + fifoFd, err := unix.Open(fifoName, unix.O_PATH|unix.O_CLOEXEC, 0) + if err != nil { + return err + } + + cmd.ExtraFiles = append(cmd.ExtraFiles, os.NewFile(uintptr(fifoFd), fifoName)) + cmd.Env = append(cmd.Env, + fmt.Sprintf("_LIBCONTAINER_FIFOFD=%d", stdioFdCount+len(cmd.ExtraFiles)-1)) return nil } -func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) { - parentPipe, childPipe, err := newPipe() +func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { + parentPipe, childPipe, err := utils.NewSockPair("init") if err != nil { - return nil, newSystemError(err) + return nil, newSystemErrorWithCause(err, "creating new init pipe") } cmd, err := c.commandTemplate(p, childPipe) if err != nil { - return nil, newSystemError(err) + return nil, newSystemErrorWithCause(err, "creating new command template") } - if !doInit { + if !p.Init { return c.newSetnsProcess(p, cmd, parentPipe, childPipe) } + + // We only set up fifoFd if we're not doing a `runc exec`. The historic + // reason for this is that previously we would pass a dirfd that allowed + // for container rootfs escape (and not doing it in `runc exec` avoided + // that problem), but we no longer do that. However, there's no need to do + // this for `runc exec` so we just keep it this way to be safe. + if err := c.includeExecFifo(cmd); err != nil { + return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup") + } return c.newInitProcess(p, cmd, parentPipe, childPipe) } func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.Cmd, error) { - cmd := &exec.Cmd{ - Path: c.initPath, - Args: c.initArgs, - } + cmd := exec.Command(c.initPath, c.initArgs[1:]...) + cmd.Args[0] = c.initArgs[0] cmd.Stdin = p.Stdin cmd.Stdout = p.Stdout cmd.Stderr = p.Stderr @@ -257,8 +470,18 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec. if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{} } - cmd.ExtraFiles = append(p.ExtraFiles, childPipe) - cmd.Env = append(cmd.Env, fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1)) + cmd.Env = append(cmd.Env, fmt.Sprintf("GOMAXPROCS=%s", os.Getenv("GOMAXPROCS"))) + cmd.ExtraFiles = append(cmd.ExtraFiles, p.ExtraFiles...) + if p.ConsoleSocket != nil { + cmd.ExtraFiles = append(cmd.ExtraFiles, p.ConsoleSocket) + cmd.Env = append(cmd.Env, + fmt.Sprintf("_LIBCONTAINER_CONSOLE=%d", stdioFdCount+len(cmd.ExtraFiles)-1), + ) + } + cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe) + cmd.Env = append(cmd.Env, + fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1), + ) // NOTE: when running a container with no PID namespace and the parent process spawning the container is // PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason // even with the parent still running. @@ -277,44 +500,48 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c } } _, sharePidns := nsMaps[configs.NEWPID] - data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps, "") + data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps) if err != nil { return nil, err } - return &initProcess{ - cmd: cmd, - childPipe: childPipe, - parentPipe: parentPipe, - manager: c.cgroupManager, - config: c.newInitConfig(p), - container: c, - process: p, - bootstrapData: data, - sharePidns: sharePidns, - }, nil + init := &initProcess{ + cmd: cmd, + childPipe: childPipe, + parentPipe: parentPipe, + manager: c.cgroupManager, + intelRdtManager: c.intelRdtManager, + config: c.newInitConfig(p), + container: c, + process: p, + bootstrapData: data, + sharePidns: sharePidns, + } + c.initProcess = init + return init, nil } func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*setnsProcess, error) { cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns)) state, err := c.currentState() if err != nil { - return nil, newSystemError(err) + return nil, newSystemErrorWithCause(err, "getting container's current state") } - // for setns process, we dont have to set cloneflags as the process namespaces + // for setns process, we don't have to set cloneflags as the process namespaces // will only be set via setns syscall - data, err := c.bootstrapData(0, state.NamespacePaths, p.consolePath) + data, err := c.bootstrapData(0, state.NamespacePaths) if err != nil { return nil, err } - // TODO: set on container for process management return &setnsProcess{ - cmd: cmd, - cgroupPaths: c.cgroupManager.GetPaths(), - childPipe: childPipe, - parentPipe: parentPipe, - config: c.newInitConfig(p), - process: p, - bootstrapData: data, + cmd: cmd, + cgroupPaths: c.cgroupManager.GetPaths(), + rootlessCgroups: c.config.RootlessCgroups, + intelRdtPath: state.IntelRdtPath, + childPipe: childPipe, + parentPipe: parentPipe, + config: c.newInitConfig(p), + process: p, + bootstrapData: data, }, nil } @@ -324,12 +551,14 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { Args: process.Args, Env: process.Env, User: process.User, + AdditionalGroups: process.AdditionalGroups, Cwd: process.Cwd, - Console: process.consolePath, Capabilities: process.Capabilities, PassedFilesCount: len(process.ExtraFiles), ContainerId: c.ID(), NoNewPrivileges: c.config.NoNewPrivileges, + RootlessEUID: c.config.RootlessEUID, + RootlessCgroups: c.config.RootlessCgroups, AppArmorProfile: c.config.AppArmorProfile, ProcessLabel: c.config.ProcessLabel, Rlimits: c.config.Rlimits, @@ -346,17 +575,12 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { if len(process.Rlimits) > 0 { cfg.Rlimits = process.Rlimits } + cfg.CreateConsole = process.ConsoleSocket != nil + cfg.ConsoleWidth = process.ConsoleWidth + cfg.ConsoleHeight = process.ConsoleHeight return cfg } -func newPipe() (parent *os.File, child *os.File, err error) { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0) - if err != nil { - return nil, nil, err - } - return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil -} - func (c *linuxContainer) Destroy() error { c.m.Lock() defer c.m.Unlock() @@ -370,15 +594,16 @@ func (c *linuxContainer) Pause() error { if err != nil { return err } - if status != Running { - return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning) - } - if err := c.cgroupManager.Freeze(configs.Frozen); err != nil { - return err + switch status { + case Running, Created: + if err := c.cgroupManager.Freeze(configs.Frozen); err != nil { + return err + } + return c.state.transition(&pausedState{ + c: c, + }) } - return c.state.transition(&pausedState{ - c: c, - }) + return newGenericError(fmt.Errorf("container not running or created: %s", status), ContainerNotRunning) } func (c *linuxContainer) Resume() error { @@ -400,36 +625,93 @@ func (c *linuxContainer) Resume() error { } func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) { + // XXX(cyphar): This requires cgroups. + if c.config.RootlessCgroups { + logrus.Warn("getting OOM notifications may fail if you don't have the full access to cgroups") + } return notifyOnOOM(c.cgroupManager.GetPaths()) } func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) { + // XXX(cyphar): This requires cgroups. + if c.config.RootlessCgroups { + logrus.Warn("getting memory pressure notifications may fail if you don't have the full access to cgroups") + } return notifyMemoryPressure(c.cgroupManager.GetPaths(), level) } -// XXX debug support, remove when debugging done. -func addArgsFromEnv(evar string, args *[]string) { - if e := os.Getenv(evar); e != "" { - for _, f := range strings.Fields(e) { - *args = append(*args, f) - } +var criuFeatures *criurpc.CriuFeatures + +func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error { + + var t criurpc.CriuReqType + t = criurpc.CriuReqType_FEATURE_CHECK + + // criu 1.8 => 10800 + if err := c.checkCriuVersion(10800); err != nil { + // Feature checking was introduced with CRIU 1.8. + // Ignore the feature check if an older CRIU version is used + // and just act as before. + // As all automated PR testing is done using CRIU 1.7 this + // code will not be tested by automated PR testing. + return nil } - fmt.Printf(">>> criu %v\n", *args) -} -// check Criu version greater than or equal to min_version -func (c *linuxContainer) checkCriuVersion(min_version string) error { - var x, y, z, versionReq int + // make sure the features we are looking for are really not from + // some previous check + criuFeatures = nil + + req := &criurpc.CriuReq{ + Type: &t, + // Theoretically this should not be necessary but CRIU + // segfaults if Opts is empty. + // Fixed in CRIU 2.12 + Opts: rpcOpts, + Features: criuFeat, + } - _, err := fmt.Sscanf(min_version, "%d.%d.%d\n", &x, &y, &z) // 1.5.2 + err := c.criuSwrk(nil, req, criuOpts, false, nil) if err != nil { - _, err = fmt.Sscanf(min_version, "Version: %d.%d\n", &x, &y) // 1.6 + logrus.Debugf("%s", err) + return fmt.Errorf("CRIU feature check failed") } - versionReq = x*10000 + y*100 + z - out, err := exec.Command(c.criuPath, "-V").Output() + logrus.Debugf("Feature check says: %s", criuFeatures) + missingFeatures := false + + // The outer if checks if the fields actually exist + if (criuFeat.MemTrack != nil) && + (criuFeatures.MemTrack != nil) { + // The inner if checks if they are set to true + if *criuFeat.MemTrack && !*criuFeatures.MemTrack { + missingFeatures = true + logrus.Debugf("CRIU does not support MemTrack") + } + } + + // This needs to be repeated for every new feature check. + // Is there a way to put this in a function. Reflection? + if (criuFeat.LazyPages != nil) && + (criuFeatures.LazyPages != nil) { + if *criuFeat.LazyPages && !*criuFeatures.LazyPages { + missingFeatures = true + logrus.Debugf("CRIU does not support LazyPages") + } + } + + if missingFeatures { + return fmt.Errorf("CRIU is missing features") + } + + return nil +} + +func parseCriuVersion(path string) (int, error) { + var x, y, z int + + out, err := exec.Command(path, "-V").Output() if err != nil { - return fmt.Errorf("Unable to execute CRIU command: %s", c.criuPath) + return 0, fmt.Errorf("Unable to execute CRIU command: %s", path) } x = 0 @@ -441,18 +723,18 @@ func (c *linuxContainer) checkCriuVersion(min_version string) error { if sp := strings.Index(string(out), "GitID"); sp > 0 { version = string(out)[sp:ep] } else { - return fmt.Errorf("Unable to parse the CRIU version: %s", c.criuPath) + return 0, fmt.Errorf("Unable to parse the CRIU version: %s", path) } - n, err := fmt.Sscanf(string(version), "GitID: v%d.%d.%d", &x, &y, &z) // 1.5.2 + n, err := fmt.Sscanf(version, "GitID: v%d.%d.%d", &x, &y, &z) // 1.5.2 if err != nil { - n, err = fmt.Sscanf(string(version), "GitID: v%d.%d", &x, &y) // 1.6 + n, err = fmt.Sscanf(version, "GitID: v%d.%d", &x, &y) // 1.6 y++ } else { z++ } if n < 2 || err != nil { - return fmt.Errorf("Unable to parse the CRIU version: %s %d %s", version, n, err) + return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", version, n, err) } } else { // criu release version format @@ -461,19 +743,81 @@ func (c *linuxContainer) checkCriuVersion(min_version string) error { n, err = fmt.Sscanf(string(out), "Version: %d.%d\n", &x, &y) // 1.6 } if n < 2 || err != nil { - return fmt.Errorf("Unable to parse the CRIU version: %s %d %s", out, n, err) + return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", out, n, err) } } - c.criuVersion = x*10000 + y*100 + z + return x*10000 + y*100 + z, nil +} - if c.criuVersion < versionReq { - return fmt.Errorf("CRIU version must be %s or higher", min_version) +func compareCriuVersion(criuVersion int, minVersion int) error { + // simple function to perform the actual version compare + if criuVersion < minVersion { + return fmt.Errorf("CRIU version %d must be %d or higher", criuVersion, minVersion) } return nil } +// This is used to store the result of criu version RPC +var criuVersionRPC *criurpc.CriuVersion + +// checkCriuVersion checks Criu version greater than or equal to minVersion +func (c *linuxContainer) checkCriuVersion(minVersion int) error { + + // If the version of criu has already been determined there is no need + // to ask criu for the version again. Use the value from c.criuVersion. + if c.criuVersion != 0 { + return compareCriuVersion(c.criuVersion, minVersion) + } + + // First try if this version of CRIU support the version RPC. + // The CRIU version RPC was introduced with CRIU 3.0. + + // First, reset the variable for the RPC answer to nil + criuVersionRPC = nil + + var t criurpc.CriuReqType + t = criurpc.CriuReqType_VERSION + req := &criurpc.CriuReq{ + Type: &t, + } + + err := c.criuSwrk(nil, req, nil, false, nil) + if err != nil { + return fmt.Errorf("CRIU version check failed: %s", err) + } + + if criuVersionRPC != nil { + logrus.Debugf("CRIU version: %s", criuVersionRPC) + // major and minor are always set + c.criuVersion = int(*criuVersionRPC.Major) * 10000 + c.criuVersion += int(*criuVersionRPC.Minor) * 100 + if criuVersionRPC.Sublevel != nil { + c.criuVersion += int(*criuVersionRPC.Sublevel) + } + if criuVersionRPC.Gitid != nil { + // runc's convention is that a CRIU git release is + // always the same as increasing the minor by 1 + c.criuVersion -= (c.criuVersion % 100) + c.criuVersion += 100 + } + return compareCriuVersion(c.criuVersion, minVersion) + } + + // This is CRIU without the version RPC and therefore + // older than 3.0. Parsing the output is required. + + // This can be remove once runc does not work with criu older than 3.0 + + c.criuVersion, err = parseCriuVersion(c.criuPath) + if err != nil { + return err + } + + return compareCriuVersion(c.criuVersion, minVersion) +} + const descriptorsFilename = "descriptors.json" func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) { @@ -489,11 +833,86 @@ func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) } +func (c *linuxContainer) addMaskPaths(req *criurpc.CriuReq) error { + for _, path := range c.config.MaskPaths { + fi, err := os.Stat(fmt.Sprintf("/proc/%d/root/%s", c.initProcess.pid(), path)) + if err != nil { + if os.IsNotExist(err) { + continue + } + return err + } + if fi.IsDir() { + continue + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(path), + Val: proto.String("/dev/null"), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + } + return nil +} + +func waitForCriuLazyServer(r *os.File, status string) error { + + data := make([]byte, 1) + _, err := r.Read(data) + if err != nil { + return err + } + fd, err := os.OpenFile(status, os.O_TRUNC|os.O_WRONLY, os.ModeAppend) + if err != nil { + return err + } + _, err = fd.Write(data) + if err != nil { + return err + } + fd.Close() + + return nil +} + +func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts) { + // CRIU will evaluate a configuration starting with release 3.11. + // Settings in the configuration file will overwrite RPC settings. + // Look for annotations. The annotation 'org.criu.config' + // specifies if CRIU should use a different, container specific + // configuration file. + _, annotations := utils.Annotations(c.config.Labels) + configFile, exists := annotations["org.criu.config"] + if exists { + // If the annotation 'org.criu.config' exists and is set + // to a non-empty string, tell CRIU to use that as a + // configuration file. If the file does not exist, CRIU + // will just ignore it. + if configFile != "" { + rpcOpts.ConfigFile = proto.String(configFile) + } + // If 'org.criu.config' exists and is set to an empty + // string, a runc specific CRIU configuration file will + // be not set at all. + } else { + // If the mentioned annotation has not been found, specify + // a default CRIU configuration file. + rpcOpts.ConfigFile = proto.String("/etc/criu/runc.conf") + } +} + func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() - if err := c.checkCriuVersion("1.5.2"); err != nil { + // Checkpoint is unlikely to work if os.Geteuid() != 0 || system.RunningInUserNS(). + // (CLI prints a warning) + // TODO(avagin): Figure out how to make this work nicely. CRIU 2.0 has + // support for doing unprivileged dumps, but the setup of + // rootless containers might make this complicated. + + // criu 1.5.2 => 10502 + if err := c.checkCriuVersion(10502); err != nil { return err } @@ -528,19 +947,57 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { defer imageDir.Close() rpcOpts := criurpc.CriuOpts{ - ImagesDirFd: proto.Int32(int32(imageDir.Fd())), - WorkDirFd: proto.Int32(int32(workDir.Fd())), - LogLevel: proto.Int32(4), - LogFile: proto.String("dump.log"), - Root: proto.String(c.config.Rootfs), - ManageCgroups: proto.Bool(true), - NotifyScripts: proto.Bool(true), - Pid: proto.Int32(int32(c.initProcess.pid())), - ShellJob: proto.Bool(criuOpts.ShellJob), - LeaveRunning: proto.Bool(criuOpts.LeaveRunning), - TcpEstablished: proto.Bool(criuOpts.TcpEstablished), - ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), - FileLocks: proto.Bool(criuOpts.FileLocks), + ImagesDirFd: proto.Int32(int32(imageDir.Fd())), + WorkDirFd: proto.Int32(int32(workDir.Fd())), + LogLevel: proto.Int32(4), + LogFile: proto.String("dump.log"), + Root: proto.String(c.config.Rootfs), + ManageCgroups: proto.Bool(true), + NotifyScripts: proto.Bool(true), + Pid: proto.Int32(int32(c.initProcess.pid())), + ShellJob: proto.Bool(criuOpts.ShellJob), + LeaveRunning: proto.Bool(criuOpts.LeaveRunning), + TcpEstablished: proto.Bool(criuOpts.TcpEstablished), + ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), + FileLocks: proto.Bool(criuOpts.FileLocks), + EmptyNs: proto.Uint32(criuOpts.EmptyNs), + OrphanPtsMaster: proto.Bool(true), + AutoDedup: proto.Bool(criuOpts.AutoDedup), + LazyPages: proto.Bool(criuOpts.LazyPages), + } + + c.handleCriuConfigurationFile(&rpcOpts) + + // If the container is running in a network namespace and has + // a path to the network namespace configured, we will dump + // that network namespace as an external namespace and we + // will expect that the namespace exists during restore. + // This basically means that CRIU will ignore the namespace + // and expect to be setup correctly. + nsPath := c.config.Namespaces.PathOf(configs.NEWNET) + if nsPath != "" { + // For this to work we need at least criu 3.11.0 => 31100. + // As there was already a successful version check we will + // not error out if it fails. runc will just behave as it used + // to do and ignore external network namespaces. + err := c.checkCriuVersion(31100) + if err == nil { + // CRIU expects the information about an external namespace + // like this: --external net[<inode>]:<key> + // This <key> is always 'extRootNetNS'. + var netns syscall.Stat_t + err = syscall.Stat(nsPath, &netns) + if err != nil { + return err + } + criuExternal := fmt.Sprintf("net[%d]:extRootNetNS", netns.Ino) + rpcOpts.External = append(rpcOpts.External, criuExternal) + } + } + + fcg := c.cgroupManager.GetPaths()["freezer"] + if fcg != "" { + rpcOpts.FreezeCgroup = proto.String(fcg) } // append optional criu opts, e.g., page-server and port @@ -551,50 +1008,98 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { } } + //pre-dump may need parentImage param to complete iterative migration + if criuOpts.ParentImage != "" { + rpcOpts.ParentImg = proto.String(criuOpts.ParentImage) + rpcOpts.TrackMem = proto.Bool(true) + } + // append optional manage cgroups mode if criuOpts.ManageCgroupsMode != 0 { - if err := c.checkCriuVersion("1.7"); err != nil { + // criu 1.7 => 10700 + if err := c.checkCriuVersion(10700); err != nil { return err } - rpcOpts.ManageCgroupsMode = proto.Uint32(uint32(criuOpts.ManageCgroupsMode)) + mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + rpcOpts.ManageCgroupsMode = &mode } - t := criurpc.CriuReqType_DUMP + var t criurpc.CriuReqType + if criuOpts.PreDump { + feat := criurpc.CriuFeatures{ + MemTrack: proto.Bool(true), + } + + if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil { + return err + } + + t = criurpc.CriuReqType_PRE_DUMP + } else { + t = criurpc.CriuReqType_DUMP + } req := &criurpc.CriuReq{ Type: &t, Opts: &rpcOpts, } - for _, m := range c.config.Mounts { - switch m.Device { - case "bind": - c.addCriuDumpMount(req, m) - break - case "cgroup": - binds, err := getCgroupMounts(m) - if err != nil { - return err - } - for _, b := range binds { - c.addCriuDumpMount(req, b) + if criuOpts.LazyPages { + // lazy migration requested; check if criu supports it + feat := criurpc.CriuFeatures{ + LazyPages: proto.Bool(true), + } + + if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil { + return err + } + + statusRead, statusWrite, err := os.Pipe() + if err != nil { + return err + } + rpcOpts.StatusFd = proto.Int32(int32(statusWrite.Fd())) + go waitForCriuLazyServer(statusRead, criuOpts.StatusFd) + } + + //no need to dump these information in pre-dump + if !criuOpts.PreDump { + for _, m := range c.config.Mounts { + switch m.Device { + case "bind": + c.addCriuDumpMount(req, m) + case "cgroup": + binds, err := getCgroupMounts(m) + if err != nil { + return err + } + for _, b := range binds { + c.addCriuDumpMount(req, b) + } } - break } - } - // Write the FD info to a file in the image directory + if err := c.addMaskPaths(req); err != nil { + return err + } - fdsJSON, err := json.Marshal(c.initProcess.externalDescriptors()) - if err != nil { - return err - } + for _, node := range c.config.Devices { + m := &configs.Mount{Destination: node.Path, Source: node.Path} + c.addCriuDumpMount(req, m) + } - err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0655) - if err != nil { - return err + // Write the FD info to a file in the image directory + fdsJSON, err := json.Marshal(c.initProcess.externalDescriptors()) + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0655) + if err != nil { + return err + } } - err = c.criuSwrk(nil, req, criuOpts, false) + err = c.criuSwrk(nil, req, criuOpts, false, nil) if err != nil { return err } @@ -614,10 +1119,39 @@ func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mo req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) } +func (c *linuxContainer) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts) { + for _, iface := range c.config.Networks { + switch iface.Type { + case "veth": + veth := new(criurpc.CriuVethPair) + veth.IfOut = proto.String(iface.HostInterfaceName) + veth.IfIn = proto.String(iface.Name) + req.Opts.Veths = append(req.Opts.Veths, veth) + case "loopback": + // Do nothing + } + } + for _, i := range criuOpts.VethPairs { + veth := new(criurpc.CriuVethPair) + veth.IfOut = proto.String(i.HostInterfaceName) + veth.IfIn = proto.String(i.ContainerInterfaceName) + req.Opts.Veths = append(req.Opts.Veths, veth) + } +} + func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() - if err := c.checkCriuVersion("1.5.2"); err != nil { + + var extraFiles []*os.File + + // Restore is unlikely to work if os.Geteuid() != 0 || system.RunningInUserNS(). + // (CLI prints a warning) + // TODO(avagin): Figure out how to make this work nicely. CRIU doesn't have + // support for unprivileged restore at the moment. + + // criu 1.5.2 => 10502 + if err := c.checkCriuVersion(10502); err != nil { return err } if criuOpts.WorkDirectory == "" { @@ -655,36 +1189,73 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { if err != nil { return err } - err = syscall.Mount(c.config.Rootfs, root, "", syscall.MS_BIND|syscall.MS_REC, "") + err = unix.Mount(c.config.Rootfs, root, "", unix.MS_BIND|unix.MS_REC, "") if err != nil { return err } - defer syscall.Unmount(root, syscall.MNT_DETACH) + defer unix.Unmount(root, unix.MNT_DETACH) t := criurpc.CriuReqType_RESTORE req := &criurpc.CriuReq{ Type: &t, Opts: &criurpc.CriuOpts{ - ImagesDirFd: proto.Int32(int32(imageDir.Fd())), - WorkDirFd: proto.Int32(int32(workDir.Fd())), - EvasiveDevices: proto.Bool(true), - LogLevel: proto.Int32(4), - LogFile: proto.String("restore.log"), - RstSibling: proto.Bool(true), - Root: proto.String(root), - ManageCgroups: proto.Bool(true), - NotifyScripts: proto.Bool(true), - ShellJob: proto.Bool(criuOpts.ShellJob), - ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), - TcpEstablished: proto.Bool(criuOpts.TcpEstablished), - FileLocks: proto.Bool(criuOpts.FileLocks), + ImagesDirFd: proto.Int32(int32(imageDir.Fd())), + WorkDirFd: proto.Int32(int32(workDir.Fd())), + EvasiveDevices: proto.Bool(true), + LogLevel: proto.Int32(4), + LogFile: proto.String("restore.log"), + RstSibling: proto.Bool(true), + Root: proto.String(root), + ManageCgroups: proto.Bool(true), + NotifyScripts: proto.Bool(true), + ShellJob: proto.Bool(criuOpts.ShellJob), + ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), + TcpEstablished: proto.Bool(criuOpts.TcpEstablished), + FileLocks: proto.Bool(criuOpts.FileLocks), + EmptyNs: proto.Uint32(criuOpts.EmptyNs), + OrphanPtsMaster: proto.Bool(true), + AutoDedup: proto.Bool(criuOpts.AutoDedup), + LazyPages: proto.Bool(criuOpts.LazyPages), }, } + c.handleCriuConfigurationFile(req.Opts) + + // Same as during checkpointing. If the container has a specific network namespace + // assigned to it, this now expects that the checkpoint will be restored in a + // already created network namespace. + nsPath := c.config.Namespaces.PathOf(configs.NEWNET) + if nsPath != "" { + // For this to work we need at least criu 3.11.0 => 31100. + // As there was already a successful version check we will + // not error out if it fails. runc will just behave as it used + // to do and ignore external network namespaces. + err := c.checkCriuVersion(31100) + if err == nil { + // CRIU wants the information about an existing network namespace + // like this: --inherit-fd fd[<fd>]:<key> + // The <key> needs to be the same as during checkpointing. + // We are always using 'extRootNetNS' as the key in this. + netns, err := os.Open(nsPath) + defer netns.Close() + if err != nil { + logrus.Errorf("If a specific network namespace is defined it must exist: %s", err) + return fmt.Errorf("Requested network namespace %v does not exist", nsPath) + } + inheritFd := new(criurpc.InheritFd) + inheritFd.Key = proto.String("extRootNetNS") + // The offset of four is necessary because 0, 1, 2 and 3 is already + // used by stdin, stdout, stderr, 'criu swrk' socket. + inheritFd.Fd = proto.Int32(int32(4 + len(extraFiles))) + req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd) + // All open FDs need to be transferred to CRIU via extraFiles + extraFiles = append(extraFiles, netns) + } + } + for _, m := range c.config.Mounts { switch m.Device { case "bind": c.addCriuRestoreMount(req, m) - break case "cgroup": binds, err := getCgroupMounts(m) if err != nil { @@ -693,34 +1264,31 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { for _, b := range binds { c.addCriuRestoreMount(req, b) } - break } } - for _, iface := range c.config.Networks { - switch iface.Type { - case "veth": - veth := new(criurpc.CriuVethPair) - veth.IfOut = proto.String(iface.HostInterfaceName) - veth.IfIn = proto.String(iface.Name) - req.Opts.Veths = append(req.Opts.Veths, veth) - break - case "loopback": - break - } + + if len(c.config.MaskPaths) > 0 { + m := &configs.Mount{Destination: "/dev/null", Source: "/dev/null"} + c.addCriuRestoreMount(req, m) } - for _, i := range criuOpts.VethPairs { - veth := new(criurpc.CriuVethPair) - veth.IfOut = proto.String(i.HostInterfaceName) - veth.IfIn = proto.String(i.ContainerInterfaceName) - req.Opts.Veths = append(req.Opts.Veths, veth) + + for _, node := range c.config.Devices { + m := &configs.Mount{Destination: node.Path, Source: node.Path} + c.addCriuRestoreMount(req, m) + } + + if criuOpts.EmptyNs&unix.CLONE_NEWNET == 0 { + c.restoreNetwork(req, criuOpts) } // append optional manage cgroups mode if criuOpts.ManageCgroupsMode != 0 { - if err := c.checkCriuVersion("1.7"); err != nil { + // criu 1.7 => 10700 + if err := c.checkCriuVersion(10700); err != nil { return err } - req.Opts.ManageCgroupsMode = proto.Uint32(uint32(criuOpts.ManageCgroupsMode)) + mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + req.Opts.ManageCgroupsMode = &mode } var ( @@ -742,14 +1310,19 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd) } } - return c.criuSwrk(process, req, criuOpts, true) + return c.criuSwrk(process, req, criuOpts, true, extraFiles) } func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error { + // XXX: Do we need to deal with this case? AFAIK criu still requires root. if err := c.cgroupManager.Apply(pid); err != nil { return err } + if err := c.cgroupManager.Set(c.config); err != nil { + return newSystemError(err) + } + path := fmt.Sprintf("/proc/%d/cgroup", pid) cgroupsPaths, err := cgroups.ParseCgroupFile(path) if err != nil { @@ -767,20 +1340,39 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error { return nil } -func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, applyCgroups bool) error { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET|syscall.SOCK_CLOEXEC, 0) +func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, applyCgroups bool, extraFiles []*os.File) error { + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0) if err != nil { return err } - logPath := filepath.Join(opts.WorkDirectory, req.GetOpts().GetLogFile()) + var logPath string + if opts != nil { + logPath = filepath.Join(opts.WorkDirectory, req.GetOpts().GetLogFile()) + } else { + // For the VERSION RPC 'opts' is set to 'nil' and therefore + // opts.WorkDirectory does not exist. Set logPath to "". + logPath = "" + } criuClient := os.NewFile(uintptr(fds[0]), "criu-transport-client") + criuClientFileCon, err := net.FileConn(criuClient) + criuClient.Close() + if err != nil { + return err + } + + criuClientCon := criuClientFileCon.(*net.UnixConn) + defer criuClientCon.Close() + criuServer := os.NewFile(uintptr(fds[1]), "criu-transport-server") - defer criuClient.Close() defer criuServer.Close() args := []string{"swrk", "3"} - logrus.Debugf("Using CRIU %d at: %s", c.criuVersion, c.criuPath) + if c.criuVersion != 0 { + // If the CRIU Version is still '0' then this is probably + // the initial CRIU run to detect the version. Skip it. + logrus.Debugf("Using CRIU %d at: %s", c.criuVersion, c.criuPath) + } logrus.Debugf("Using CRIU with following args: %s", args) cmd := exec.Command(c.criuPath, args...) if process != nil { @@ -789,6 +1381,9 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * cmd.Stderr = process.Stderr } cmd.ExtraFiles = append(cmd.ExtraFiles, criuServer) + if extraFiles != nil { + cmd.ExtraFiles = append(cmd.ExtraFiles, extraFiles...) + } if err := cmd.Start(); err != nil { return err @@ -796,7 +1391,7 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * criuServer.Close() defer func() { - criuClient.Close() + criuClientCon.Close() _, err := cmd.Process.Wait() if err != nil { return @@ -819,29 +1414,38 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * } logrus.Debugf("Using CRIU in %s mode", req.GetType().String()) - val := reflect.ValueOf(req.GetOpts()) - v := reflect.Indirect(val) - for i := 0; i < v.NumField(); i++ { - st := v.Type() - name := st.Field(i).Name - if strings.HasPrefix(name, "XXX_") { - continue + // In the case of criurpc.CriuReqType_FEATURE_CHECK req.GetOpts() + // should be empty. For older CRIU versions it still will be + // available but empty. criurpc.CriuReqType_VERSION actually + // has no req.GetOpts(). + if !(req.GetType() == criurpc.CriuReqType_FEATURE_CHECK || + req.GetType() == criurpc.CriuReqType_VERSION) { + + val := reflect.ValueOf(req.GetOpts()) + v := reflect.Indirect(val) + for i := 0; i < v.NumField(); i++ { + st := v.Type() + name := st.Field(i).Name + if strings.HasPrefix(name, "XXX_") { + continue + } + value := val.MethodByName("Get" + name).Call([]reflect.Value{}) + logrus.Debugf("CRIU option %s with value %v", name, value[0]) } - value := val.MethodByName("Get" + name).Call([]reflect.Value{}) - logrus.Debugf("CRIU option %s with value %v", name, value[0]) } data, err := proto.Marshal(req) if err != nil { return err } - _, err = criuClient.Write(data) + _, err = criuClientCon.Write(data) if err != nil { return err } buf := make([]byte, 10*4096) + oob := make([]byte, 4096) for true { - n, err := criuClient.Read(buf) + n, oobn, _, _, err := criuClientCon.ReadMsgUnix(buf, oob) if err != nil { return err } @@ -859,13 +1463,25 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * } if !resp.GetSuccess() { typeString := req.GetType().String() + if typeString == "VERSION" { + // If the VERSION RPC fails this probably means that the CRIU + // version is too old for this RPC. Just return 'nil'. + return nil + } return fmt.Errorf("criu failed: type %s errno %d\nlog file: %s", typeString, resp.GetCrErrno(), logPath) } t := resp.GetType() switch { + case t == criurpc.CriuReqType_VERSION: + logrus.Debugf("CRIU version: %s", resp) + criuVersionRPC = resp.GetVersion() + break + case t == criurpc.CriuReqType_FEATURE_CHECK: + logrus.Debugf("Feature check says: %s", resp) + criuFeatures = resp.GetFeatures() case t == criurpc.CriuReqType_NOTIFY: - if err := c.criuNotifications(resp, process, opts, extFds); err != nil { + if err := c.criuNotifications(resp, process, opts, extFds, oob[:oobn]); err != nil { return err } t = criurpc.CriuReqType_NOTIFY @@ -877,14 +1493,14 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * if err != nil { return err } - n, err = criuClient.Write(data) + _, err = criuClientCon.Write(data) if err != nil { return err } continue case t == criurpc.CriuReqType_RESTORE: case t == criurpc.CriuReqType_DUMP: - break + case t == criurpc.CriuReqType_PRE_DUMP: default: return fmt.Errorf("unable to parse the response %s", resp.String()) } @@ -892,13 +1508,22 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * break } + criuClientCon.CloseWrite() // cmd.Wait() waits cmd.goroutines which are used for proxying file descriptors. // Here we want to wait only the CRIU process. st, err := cmd.Process.Wait() if err != nil { return err } - if !st.Success() { + + // In pre-dump mode CRIU is in a loop and waits for + // the final DUMP command. + // The current runc pre-dump approach, however, is + // start criu in PRE_DUMP once for a single pre-dump + // and not the whole series of pre-dump, pre-dump, ...m, dump + // If we got the message CriuReqType_PRE_DUMP it means + // CRIU was successful and we need to forcefully stop CRIU + if !st.Success() && *req.Type != criurpc.CriuReqType_PRE_DUMP { return fmt.Errorf("criu failed: %s\nlog file: %s", st.String(), logPath) } return nil @@ -932,11 +1557,12 @@ func unlockNetwork(config *configs.Config) error { return nil } -func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, opts *CriuOpts, fds []string) error { +func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, opts *CriuOpts, fds []string, oob []byte) error { notify := resp.GetNotify() if notify == nil { return fmt.Errorf("invalid response: %s", resp.String()) } + logrus.Debugf("notify: %s\n", notify.GetScript()) switch { case notify.GetScript() == "post-dump": f, err := os.Create(filepath.Join(c.root, "checkpoint")) @@ -952,6 +1578,19 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc if err := lockNetwork(c.config); err != nil { return err } + case notify.GetScript() == "setup-namespaces": + if c.config.Hooks != nil { + s, err := c.currentOCIState() + if err != nil { + return nil + } + s.Pid = int(notify.GetPid()) + for i, hook := range c.config.Hooks.Prestart { + if err := hook.Run(s); err != nil { + return newSystemErrorWithCausef(err, "running prestart hook %d", i) + } + } + } case notify.GetScript() == "post-restore": pid := notify.GetPid() r, err := newRestoredProcess(int(pid), fds) @@ -965,7 +1604,9 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc }); err != nil { return err } - if err := c.updateState(r); err != nil { + // create a timestamp indicating when the restored checkpoint was started + c.created = time.Now().UTC() + if _, err := c.updateState(r); err != nil { return err } if err := os.Remove(filepath.Join(c.root, "checkpoint")); err != nil { @@ -973,17 +1614,40 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc logrus.Error(err) } } + case notify.GetScript() == "orphan-pts-master": + scm, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return err + } + fds, err := unix.ParseUnixRights(&scm[0]) + if err != nil { + return err + } + + master := os.NewFile(uintptr(fds[0]), "orphan-pts-master") + defer master.Close() + + // While we can access console.master, using the API is a good idea. + if err := utils.SendFd(process.ConsoleSocket, master.Name(), master.Fd()); err != nil { + return err + } } return nil } -func (c *linuxContainer) updateState(process parentProcess) error { - c.initProcess = process +func (c *linuxContainer) updateState(process parentProcess) (*State, error) { + if process != nil { + c.initProcess = process + } state, err := c.currentState() if err != nil { - return err + return nil, err + } + err = c.saveState(state) + if err != nil { + return nil, err } - return c.saveState(state) + return state, nil } func (c *linuxContainer) saveState(s *State) error { @@ -1018,44 +1682,59 @@ func (c *linuxContainer) refreshState() error { if paused { return c.state.transition(&pausedState{c: c}) } - running, err := c.isRunning() + t, err := c.runType() if err != nil { return err } - if running { + switch t { + case Created: + return c.state.transition(&createdState{c: c}) + case Running: return c.state.transition(&runningState{c: c}) } return c.state.transition(&stoppedState{c: c}) } -func (c *linuxContainer) isRunning() (bool, error) { +func (c *linuxContainer) runType() (Status, error) { if c.initProcess == nil { - return false, nil + return Stopped, nil } - // return Running if the init process is alive - if err := syscall.Kill(c.initProcess.pid(), 0); err != nil { - if err == syscall.ESRCH { - return false, nil - } - return false, newSystemError(err) + pid := c.initProcess.pid() + stat, err := system.Stat(pid) + if err != nil { + return Stopped, nil + } + if stat.StartTime != c.initProcessStartTime || stat.State == system.Zombie || stat.State == system.Dead { + return Stopped, nil } - return true, nil + // We'll create exec fifo and blocking on it after container is created, + // and delete it after start container. + if _, err := os.Stat(filepath.Join(c.root, execFifoFilename)); err == nil { + return Created, nil + } + return Running, nil } func (c *linuxContainer) isPaused() (bool, error) { - data, err := ioutil.ReadFile(filepath.Join(c.cgroupManager.GetPaths()["freezer"], "freezer.state")) + fcg := c.cgroupManager.GetPaths()["freezer"] + if fcg == "" { + // A container doesn't have a freezer cgroup + return false, nil + } + data, err := ioutil.ReadFile(filepath.Join(fcg, "freezer.state")) if err != nil { + // If freezer cgroup is not mounted, the container would just be not paused. if os.IsNotExist(err) { return false, nil } - return false, newSystemError(err) + return false, newSystemErrorWithCause(err, "checking if container is paused") } return bytes.Equal(bytes.TrimSpace(data), []byte("FROZEN")), nil } func (c *linuxContainer) currentState() (*State, error) { var ( - startTime string + startTime uint64 externalDescriptors []string pid = -1 ) @@ -1064,6 +1743,10 @@ func (c *linuxContainer) currentState() (*State, error) { startTime, _ = c.initProcess.startTime() externalDescriptors = c.initProcess.externalDescriptors() } + intelRdtPath, err := intelrdt.GetIntelRdtPath(c.ID()) + if err != nil { + intelRdtPath = "" + } state := &State{ BaseState: BaseState{ ID: c.ID(), @@ -1072,7 +1755,9 @@ func (c *linuxContainer) currentState() (*State, error) { InitProcessStartTime: startTime, Created: c.created, }, + Rootless: c.config.RootlessEUID && c.config.RootlessCgroups, CgroupPaths: c.cgroupManager.GetPaths(), + IntelRdtPath: intelRdtPath, NamespacePaths: make(map[configs.NamespaceType]string), ExternalDescriptors: externalDescriptors, } @@ -1093,39 +1778,57 @@ func (c *linuxContainer) currentState() (*State, error) { return state, nil } +func (c *linuxContainer) currentOCIState() (*specs.State, error) { + bundle, annotations := utils.Annotations(c.config.Labels) + state := &specs.State{ + Version: specs.Version, + ID: c.ID(), + Bundle: bundle, + Annotations: annotations, + } + status, err := c.currentStatus() + if err != nil { + return nil, err + } + state.Status = status.String() + if status != Stopped { + if c.initProcess != nil { + state.Pid = c.initProcess.pid() + } + } + return state, nil +} + // orderNamespacePaths sorts namespace paths into a list of paths that we // can setns in order. func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) { paths := []string{} - nsTypes := []configs.NamespaceType{ - configs.NEWIPC, - configs.NEWUTS, - configs.NEWNET, - configs.NEWPID, - configs.NEWNS, - } - // join userns if the init process explicitly requires NEWUSER - if c.config.Namespaces.Contains(configs.NEWUSER) { - nsTypes = append(nsTypes, configs.NEWUSER) - } - for _, nsType := range nsTypes { - if p, ok := namespaces[nsType]; ok && p != "" { + for _, ns := range configs.NamespaceTypes() { + + // Remove namespaces that we don't need to join. + if !c.config.Namespaces.Contains(ns) { + continue + } + + if p, ok := namespaces[ns]; ok && p != "" { // check if the requested namespace is supported - if !configs.IsNamespaceSupported(nsType) { - return nil, newSystemError(fmt.Errorf("namespace %s is not supported", nsType)) + if !configs.IsNamespaceSupported(ns) { + return nil, newSystemError(fmt.Errorf("namespace %s is not supported", ns)) } // only set to join this namespace if it exists if _, err := os.Lstat(p); err != nil { - return nil, newSystemError(err) + return nil, newSystemErrorWithCausef(err, "running lstat on namespace path %q", p) } // do not allow namespace path with comma as we use it to separate // the namespace paths if strings.ContainsRune(p, ',') { return nil, newSystemError(fmt.Errorf("invalid path %s", p)) } - paths = append(paths, p) + paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(ns), p)) } + } + return paths, nil } @@ -1146,7 +1849,7 @@ func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) { // such as one that uses nsenter package to bootstrap the container's // init process correctly, i.e. with correct namespaces, uid/gid // mapping etc. -func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, consolePath string) (io.Reader, error) { +func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) { // create the netlink message r := nl.NewNetlinkRequest(int(InitMsg), 0) @@ -1156,14 +1859,6 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na Value: uint32(cloneFlags), }) - // write console path - if consolePath != "" { - r.AddData(&Bytemsg{ - Type: ConsolePathAttr, - Value: []byte(consolePath), - }) - } - // write custom namespace paths if len(nsMaps) > 0 { nsPaths, err := c.orderNamespacePaths(nsMaps) @@ -1181,6 +1876,12 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na if !joinExistingUser { // write uid mappings if len(c.config.UidMappings) > 0 { + if c.config.RootlessEUID && c.newuidmapPath != "" { + r.AddData(&Bytemsg{ + Type: UidmapPathAttr, + Value: []byte(c.newuidmapPath), + }) + } b, err := encodeIDMapping(c.config.UidMappings) if err != nil { return nil, err @@ -1193,7 +1894,7 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na // write gid mappings if len(c.config.GidMappings) > 0 { - b, err := encodeIDMapping(c.config.UidMappings) + b, err := encodeIDMapping(c.config.GidMappings) if err != nil { return nil, err } @@ -1201,12 +1902,13 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na Type: GidmapAttr, Value: b, }) - // check if we have CAP_SETGID to setgroup properly - pid, err := capability.NewPid(os.Getpid()) - if err != nil { - return nil, err + if c.config.RootlessEUID && c.newgidmapPath != "" { + r.AddData(&Bytemsg{ + Type: GidmapPathAttr, + Value: []byte(c.newgidmapPath), + }) } - if !pid.Get(capability.EFFECTIVE, capability.CAP_SETGID) { + if requiresRootOrMappingTool(c.config) { r.AddData(&Boolmsg{ Type: SetgroupAttr, Value: true, @@ -1215,5 +1917,41 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na } } + if c.config.OomScoreAdj != nil { + // write oom_score_adj + r.AddData(&Bytemsg{ + Type: OomScoreAdjAttr, + Value: []byte(fmt.Sprintf("%d", *c.config.OomScoreAdj)), + }) + } + + // write rootless + r.AddData(&Boolmsg{ + Type: RootlessEUIDAttr, + Value: c.config.RootlessEUID, + }) + return bytes.NewReader(r.Serialize()), nil } + +// ignoreTerminateErrors returns nil if the given err matches an error known +// to indicate that the terminate occurred successfully or err was nil, otherwise +// err is returned unaltered. +func ignoreTerminateErrors(err error) error { + if err == nil { + return nil + } + s := err.Error() + switch { + case strings.Contains(s, "process already finished"), strings.Contains(s, "Wait was already called"): + return nil + } + return err +} + +func requiresRootOrMappingTool(c *configs.Config) bool { + gidMap := []configs.IDMap{ + {ContainerID: 0, HostID: os.Getegid(), Size: 1}, + } + return !reflect.DeepEqual(c.GidMappings, gidMap) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux_test.go index 3af30bce9707ee50dbdb7793245a2f20f3ca69b0..29ddbfad30d4c28150b27b4ccd485f5df97aa133 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux_test.go @@ -4,11 +4,14 @@ package libcontainer import ( "fmt" + "io/ioutil" "os" "testing" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/system" ) type mockCgroupManager struct { @@ -18,6 +21,11 @@ type mockCgroupManager struct { paths map[string]string } +type mockIntelRdtManager struct { + stats *intelrdt.Stats + path string +} + func (m *mockCgroupManager) GetPids() ([]int, error) { return m.pids, nil } @@ -50,9 +58,29 @@ func (m *mockCgroupManager) Freeze(state configs.FreezerState) error { return nil } +func (m *mockIntelRdtManager) Apply(pid int) error { + return nil +} + +func (m *mockIntelRdtManager) GetStats() (*intelrdt.Stats, error) { + return m.stats, nil +} + +func (m *mockIntelRdtManager) Destroy() error { + return nil +} + +func (m *mockIntelRdtManager) GetPath() string { + return m.path +} + +func (m *mockIntelRdtManager) Set(container *configs.Config) error { + return nil +} + type mockProcess struct { _pid int - started string + started uint64 } func (m *mockProcess) terminate() error { @@ -63,7 +91,7 @@ func (m *mockProcess) pid() int { return m._pid } -func (m *mockProcess) startTime() (string, error) { +func (m *mockProcess) startTime() (uint64, error) { return m.started, nil } @@ -79,11 +107,11 @@ func (m *mockProcess) signal(_ os.Signal) error { return nil } -func (p *mockProcess) externalDescriptors() []string { +func (m *mockProcess) externalDescriptors() []string { return []string{} } -func (p *mockProcess) setExternalDescriptors(newFds []string) { +func (m *mockProcess) setExternalDescriptors(newFds []string) { } func TestGetContainerPids(t *testing.T) { @@ -117,6 +145,12 @@ func TestGetContainerStats(t *testing.T) { }, }, }, + intelRdtManager: &mockIntelRdtManager{ + stats: &intelrdt.Stats{ + L3CacheSchema: "L3:0=f;1=f0", + MemBwSchema: "MB:0=20;1=70", + }, + }, } stats, err := container.Stats() if err != nil { @@ -126,15 +160,32 @@ func TestGetContainerStats(t *testing.T) { t.Fatal("cgroup stats are nil") } if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 { - t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage) + t.Fatalf("expected memory usage 1024 but received %d", stats.CgroupStats.MemoryStats.Usage.Usage) + } + if intelrdt.IsCatEnabled() { + if stats.IntelRdtStats == nil { + t.Fatal("intel rdt stats are nil") + } + if stats.IntelRdtStats.L3CacheSchema != "L3:0=f;1=f0" { + t.Fatalf("expected L3CacheSchema L3:0=f;1=f0 but received %s", stats.IntelRdtStats.L3CacheSchema) + } + } + if intelrdt.IsMbaEnabled() { + if stats.IntelRdtStats == nil { + t.Fatal("intel rdt stats are nil") + } + if stats.IntelRdtStats.MemBwSchema != "MB:0=20;1=70" { + t.Fatalf("expected MemBwSchema MB:0=20;1=70 but received %s", stats.IntelRdtStats.MemBwSchema) + } } } func TestGetContainerState(t *testing.T) { var ( - pid = os.Getpid() - expectedMemoryPath = "/sys/fs/cgroup/memory/myid" - expectedNetworkPath = "/networks/fd" + pid = os.Getpid() + expectedMemoryPath = "/sys/fs/cgroup/memory/myid" + expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid) + expectedIntelRdtPath = "/sys/fs/resctrl/myid" ) container := &linuxContainer{ id: "myid", @@ -150,7 +201,7 @@ func TestGetContainerState(t *testing.T) { }, initProcess: &mockProcess{ _pid: pid, - started: "010", + started: 10, }, cgroupManager: &mockCgroupManager{ pids: []int{1, 2, 3}, @@ -165,6 +216,13 @@ func TestGetContainerState(t *testing.T) { "memory": expectedMemoryPath, }, }, + intelRdtManager: &mockIntelRdtManager{ + stats: &intelrdt.Stats{ + L3CacheSchema: "L3:0=f0;1=f", + MemBwSchema: "MB:0=70;1=20", + }, + path: expectedIntelRdtPath, + }, } container.state = &createdState{c: container} state, err := container.State() @@ -174,8 +232,8 @@ func TestGetContainerState(t *testing.T) { if state.InitProcessPid != pid { t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid) } - if state.InitProcessStartTime != "010" { - t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime) + if state.InitProcessStartTime != 10 { + t.Fatalf("expected process start time 10 but received %d", state.InitProcessStartTime) } paths := state.CgroupPaths if paths == nil { @@ -184,6 +242,15 @@ func TestGetContainerState(t *testing.T) { if memPath := paths["memory"]; memPath != expectedMemoryPath { t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) } + if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() { + intelRdtPath := state.IntelRdtPath + if intelRdtPath == "" { + t.Fatal("intel rdt path should not be empty") + } + if intelRdtPath != expectedIntelRdtPath { + t.Fatalf("expected intel rdt path %q but received %q", expectedIntelRdtPath, intelRdtPath) + } + } for _, ns := range container.config.Namespaces { path := state.NamespacePaths[ns.Type] if path == "" { @@ -216,3 +283,73 @@ func TestGetContainerState(t *testing.T) { } } } + +func TestGetContainerStateAfterUpdate(t *testing.T) { + var ( + pid = os.Getpid() + ) + stat, err := system.Stat(pid) + if err != nil { + t.Fatal(err) + } + + rootDir, err := ioutil.TempDir("", "TestGetContainerStateAfterUpdate") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(rootDir) + + container := &linuxContainer{ + root: rootDir, + id: "myid", + config: &configs.Config{ + Namespaces: []configs.Namespace{ + {Type: configs.NEWPID}, + {Type: configs.NEWNS}, + {Type: configs.NEWNET}, + {Type: configs.NEWUTS}, + {Type: configs.NEWIPC}, + }, + Cgroups: &configs.Cgroup{ + Resources: &configs.Resources{ + Memory: 1024, + }, + }, + }, + initProcess: &mockProcess{ + _pid: pid, + started: stat.StartTime, + }, + cgroupManager: &mockCgroupManager{}, + } + container.state = &createdState{c: container} + state, err := container.State() + if err != nil { + t.Fatal(err) + } + if state.InitProcessPid != pid { + t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid) + } + if state.InitProcessStartTime != stat.StartTime { + t.Fatalf("expected process start time %d but received %d", stat.StartTime, state.InitProcessStartTime) + } + if state.Config.Cgroups.Resources.Memory != 1024 { + t.Fatalf("expected Memory to be 1024 but received %q", state.Config.Cgroups.Memory) + } + + // Set initProcessStartTime so we fake to be running + container.initProcessStartTime = state.InitProcessStartTime + container.state = &runningState{c: container} + newConfig := container.Config() + newConfig.Cgroups.Resources.Memory = 2048 + if err := container.Set(newConfig); err != nil { + t.Fatal(err) + } + state, err = container.State() + if err != nil { + t.Fatal(err) + } + if state.Config.Cgroups.Resources.Memory != 2048 { + t.Fatalf("expected Memory to be 2048 but received %q", state.Config.Cgroups.Memory) + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/container_windows.go deleted file mode 100644 index bb84ff7402b9176f445fc524918afbad49867da8..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_windows.go +++ /dev/null @@ -1,20 +0,0 @@ -package libcontainer - -// State represents a running container's state -type State struct { - BaseState - - // Platform specific fields below here -} - -// A libcontainer container object. -// -// Each container is thread-safe within the same process. Since a container can -// be destroyed by a separate process, any function may return that the container -// was not found. -type Container interface { - BaseContainer - - // Methods below here are platform specific - -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go similarity index 52% rename from vendor/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go rename to vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go index a2a816bd952ea14b081f8ea43e2be7bd2e07d9e9..a2e344fc4b67248d1e6f728b7478856b24d4eb65 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go @@ -1,15 +1,13 @@ -// +build linux freebsd - package libcontainer // cgroup restoring strategy provided by criu -type cg_mode uint32 +type cgMode uint32 const ( - CRIU_CG_MODE_SOFT cg_mode = 3 + iota // restore cgroup properties if only dir created by criu - CRIU_CG_MODE_FULL // always restore all cgroups and their properties - CRIU_CG_MODE_STRICT // restore all, requiring them to not present in the system - CRIU_CG_MODE_DEFAULT // the same as CRIU_CG_MODE_SOFT + CRIU_CG_MODE_SOFT cgMode = 3 + iota // restore cgroup properties if only dir created by criu + CRIU_CG_MODE_FULL // always restore all cgroups and their properties + CRIU_CG_MODE_STRICT // restore all, requiring them to not present in the system + CRIU_CG_MODE_DEFAULT // the same as CRIU_CG_MODE_SOFT ) type CriuPageServerInfo struct { @@ -25,12 +23,18 @@ type VethPairName struct { type CriuOpts struct { ImagesDirectory string // directory for storing image files WorkDirectory string // directory to cd and write logs/pidfiles/stats to + ParentImage string // directory for storing parent image files in pre-dump and dump LeaveRunning bool // leave container in running state after checkpoint TcpEstablished bool // checkpoint/restore established TCP connections ExternalUnixConnections bool // allow external unix connections ShellJob bool // allow to dump and restore shell jobs FileLocks bool // handle file locks, for safety + PreDump bool // call criu predump to perform iterative checkpoint PageServer CriuPageServerInfo // allow to dump to criu page server VethPairs []VethPairName // pass the veth to criu when restore - ManageCgroupsMode cg_mode // dump or restore cgroup mode + ManageCgroupsMode cgMode // dump or restore cgroup mode + EmptyNs uint32 // don't c/r properties for namespace from this mask + AutoDedup bool // auto deduplication for incremental dumps + LazyPages bool // restore memory pages lazily using userfaultfd + StatusFd string // fd for feedback when lazy server is ready } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go deleted file mode 100644 index bc9207703a1dee26b46818a1815843557855db04..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package libcontainer - -// TODO Windows: This can ultimately be entirely factored out as criu is -// a Unix concept not relevant on Windows. -type CriuOpts struct { -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.pb.go b/vendor/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.pb.go index 193b6df1db27209d00b55418adca34f6b5bad874..1332d3fe3fc9cac65b7a6c14d788cf4297668ed9 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.pb.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/criurpc/criurpc.pb.go @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: criurpc.proto -// DO NOT EDIT! /* Package criurpc is a generated protocol buffer package. @@ -12,6 +11,7 @@ It has these top-level messages: CriuPageServerInfo CriuVethPair ExtMountMap + JoinNamespace InheritFd CgroupRoot UnixSk @@ -19,18 +19,77 @@ It has these top-level messages: CriuDumpResp CriuRestoreResp CriuNotify + CriuFeatures CriuReq CriuResp + CriuVersion */ package criurpc import proto "github.com/golang/protobuf/proto" +import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal +var _ = fmt.Errorf var _ = math.Inf +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CriuCgMode int32 + +const ( + CriuCgMode_IGNORE CriuCgMode = 0 + CriuCgMode_CG_NONE CriuCgMode = 1 + CriuCgMode_PROPS CriuCgMode = 2 + CriuCgMode_SOFT CriuCgMode = 3 + CriuCgMode_FULL CriuCgMode = 4 + CriuCgMode_STRICT CriuCgMode = 5 + CriuCgMode_DEFAULT CriuCgMode = 6 +) + +var CriuCgMode_name = map[int32]string{ + 0: "IGNORE", + 1: "CG_NONE", + 2: "PROPS", + 3: "SOFT", + 4: "FULL", + 5: "STRICT", + 6: "DEFAULT", +} +var CriuCgMode_value = map[string]int32{ + "IGNORE": 0, + "CG_NONE": 1, + "PROPS": 2, + "SOFT": 3, + "FULL": 4, + "STRICT": 5, + "DEFAULT": 6, +} + +func (x CriuCgMode) Enum() *CriuCgMode { + p := new(CriuCgMode) + *p = x + return p +} +func (x CriuCgMode) String() string { + return proto.EnumName(CriuCgMode_name, int32(x)) +} +func (x *CriuCgMode) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(CriuCgMode_value, data, "CriuCgMode") + if err != nil { + return err + } + *x = CriuCgMode(value) + return nil +} +func (CriuCgMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + type CriuReqType int32 const ( @@ -43,18 +102,22 @@ const ( CriuReqType_NOTIFY CriuReqType = 6 CriuReqType_CPUINFO_DUMP CriuReqType = 7 CriuReqType_CPUINFO_CHECK CriuReqType = 8 + CriuReqType_FEATURE_CHECK CriuReqType = 9 + CriuReqType_VERSION CriuReqType = 10 ) var CriuReqType_name = map[int32]string{ - 0: "EMPTY", - 1: "DUMP", - 2: "RESTORE", - 3: "CHECK", - 4: "PRE_DUMP", - 5: "PAGE_SERVER", - 6: "NOTIFY", - 7: "CPUINFO_DUMP", - 8: "CPUINFO_CHECK", + 0: "EMPTY", + 1: "DUMP", + 2: "RESTORE", + 3: "CHECK", + 4: "PRE_DUMP", + 5: "PAGE_SERVER", + 6: "NOTIFY", + 7: "CPUINFO_DUMP", + 8: "CPUINFO_CHECK", + 9: "FEATURE_CHECK", + 10: "VERSION", } var CriuReqType_value = map[string]int32{ "EMPTY": 0, @@ -66,6 +129,8 @@ var CriuReqType_value = map[string]int32{ "NOTIFY": 6, "CPUINFO_DUMP": 7, "CPUINFO_CHECK": 8, + "FEATURE_CHECK": 9, + "VERSION": 10, } func (x CriuReqType) Enum() *CriuReqType { @@ -84,6 +149,7 @@ func (x *CriuReqType) UnmarshalJSON(data []byte) error { *x = CriuReqType(value) return nil } +func (CriuReqType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } type CriuPageServerInfo struct { Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` @@ -93,9 +159,10 @@ type CriuPageServerInfo struct { XXX_unrecognized []byte `json:"-"` } -func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} } -func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) } -func (*CriuPageServerInfo) ProtoMessage() {} +func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} } +func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) } +func (*CriuPageServerInfo) ProtoMessage() {} +func (*CriuPageServerInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (m *CriuPageServerInfo) GetAddress() string { if m != nil && m.Address != nil { @@ -126,14 +193,15 @@ func (m *CriuPageServerInfo) GetFd() int32 { } type CriuVethPair struct { - IfIn *string `protobuf:"bytes,1,req,name=if_in" json:"if_in,omitempty"` - IfOut *string `protobuf:"bytes,2,req,name=if_out" json:"if_out,omitempty"` + IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"` + IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"` XXX_unrecognized []byte `json:"-"` } -func (m *CriuVethPair) Reset() { *m = CriuVethPair{} } -func (m *CriuVethPair) String() string { return proto.CompactTextString(m) } -func (*CriuVethPair) ProtoMessage() {} +func (m *CriuVethPair) Reset() { *m = CriuVethPair{} } +func (m *CriuVethPair) String() string { return proto.CompactTextString(m) } +func (*CriuVethPair) ProtoMessage() {} +func (*CriuVethPair) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } func (m *CriuVethPair) GetIfIn() string { if m != nil && m.IfIn != nil { @@ -155,9 +223,10 @@ type ExtMountMap struct { XXX_unrecognized []byte `json:"-"` } -func (m *ExtMountMap) Reset() { *m = ExtMountMap{} } -func (m *ExtMountMap) String() string { return proto.CompactTextString(m) } -func (*ExtMountMap) ProtoMessage() {} +func (m *ExtMountMap) Reset() { *m = ExtMountMap{} } +func (m *ExtMountMap) String() string { return proto.CompactTextString(m) } +func (*ExtMountMap) ProtoMessage() {} +func (*ExtMountMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } func (m *ExtMountMap) GetKey() string { if m != nil && m.Key != nil { @@ -173,15 +242,49 @@ func (m *ExtMountMap) GetVal() string { return "" } +type JoinNamespace struct { + Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"` + NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"` + ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *JoinNamespace) Reset() { *m = JoinNamespace{} } +func (m *JoinNamespace) String() string { return proto.CompactTextString(m) } +func (*JoinNamespace) ProtoMessage() {} +func (*JoinNamespace) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *JoinNamespace) GetNs() string { + if m != nil && m.Ns != nil { + return *m.Ns + } + return "" +} + +func (m *JoinNamespace) GetNsFile() string { + if m != nil && m.NsFile != nil { + return *m.NsFile + } + return "" +} + +func (m *JoinNamespace) GetExtraOpt() string { + if m != nil && m.ExtraOpt != nil { + return *m.ExtraOpt + } + return "" +} + type InheritFd struct { Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"` XXX_unrecognized []byte `json:"-"` } -func (m *InheritFd) Reset() { *m = InheritFd{} } -func (m *InheritFd) String() string { return proto.CompactTextString(m) } -func (*InheritFd) ProtoMessage() {} +func (m *InheritFd) Reset() { *m = InheritFd{} } +func (m *InheritFd) String() string { return proto.CompactTextString(m) } +func (*InheritFd) ProtoMessage() {} +func (*InheritFd) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (m *InheritFd) GetKey() string { if m != nil && m.Key != nil { @@ -203,9 +306,10 @@ type CgroupRoot struct { XXX_unrecognized []byte `json:"-"` } -func (m *CgroupRoot) Reset() { *m = CgroupRoot{} } -func (m *CgroupRoot) String() string { return proto.CompactTextString(m) } -func (*CgroupRoot) ProtoMessage() {} +func (m *CgroupRoot) Reset() { *m = CgroupRoot{} } +func (m *CgroupRoot) String() string { return proto.CompactTextString(m) } +func (*CgroupRoot) ProtoMessage() {} +func (*CgroupRoot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (m *CgroupRoot) GetCtrl() string { if m != nil && m.Ctrl != nil { @@ -226,9 +330,10 @@ type UnixSk struct { XXX_unrecognized []byte `json:"-"` } -func (m *UnixSk) Reset() { *m = UnixSk{} } -func (m *UnixSk) String() string { return proto.CompactTextString(m) } -func (*UnixSk) ProtoMessage() {} +func (m *UnixSk) Reset() { *m = UnixSk{} } +func (m *UnixSk) String() string { return proto.CompactTextString(m) } +func (*UnixSk) ProtoMessage() {} +func (*UnixSk) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (m *UnixSk) GetInode() uint32 { if m != nil && m.Inode != nil { @@ -238,49 +343,67 @@ func (m *UnixSk) GetInode() uint32 { } type CriuOpts struct { - ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd" json:"images_dir_fd,omitempty"` - Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` - LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running" json:"leave_running,omitempty"` - ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk" json:"ext_unix_sk,omitempty"` - TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established" json:"tcp_established,omitempty"` - EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices" json:"evasive_devices,omitempty"` - ShellJob *bool `protobuf:"varint,7,opt,name=shell_job" json:"shell_job,omitempty"` - FileLocks *bool `protobuf:"varint,8,opt,name=file_locks" json:"file_locks,omitempty"` - LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,def=2" json:"log_level,omitempty"` - LogFile *string `protobuf:"bytes,10,opt,name=log_file" json:"log_file,omitempty"` - Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"` - NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts" json:"notify_scripts,omitempty"` - Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"` - ParentImg *string `protobuf:"bytes,14,opt,name=parent_img" json:"parent_img,omitempty"` - TrackMem *bool `protobuf:"varint,15,opt,name=track_mem" json:"track_mem,omitempty"` - AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup" json:"auto_dedup,omitempty"` - WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd" json:"work_dir_fd,omitempty"` - LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap" json:"link_remap,omitempty"` - Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"` - CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,def=4294967295" json:"cpu_cap,omitempty"` - ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap" json:"force_irmap,omitempty"` - ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd" json:"exec_cmd,omitempty"` - ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt" json:"ext_mnt,omitempty"` - ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups" json:"manage_cgroups,omitempty"` - CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root" json:"cg_root,omitempty"` - RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling" json:"rst_sibling,omitempty"` - InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd" json:"inherit_fd,omitempty"` - AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt" json:"auto_ext_mnt,omitempty"` - ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing" json:"ext_sharing,omitempty"` - ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters" json:"ext_masters,omitempty"` - SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt" json:"skip_mnt,omitempty"` - EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs" json:"enable_fs,omitempty"` - UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino" json:"unix_sk_ino,omitempty"` - ManageCgroupsMode *uint32 `protobuf:"varint,34,opt,name=manage_cgroups_mode" json:"manage_cgroups_mode,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *CriuOpts) Reset() { *m = CriuOpts{} } -func (m *CriuOpts) String() string { return proto.CompactTextString(m) } -func (*CriuOpts) ProtoMessage() {} + ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"` + Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` + LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"` + ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"` + TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"` + EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"` + ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"` + FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"` + LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"` + LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"` + Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"` + NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"` + Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"` + ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"` + TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"` + AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"` + WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"` + LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"` + Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"` + CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"` + ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"` + ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"` + ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"` + ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"` + CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"` + RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"` + InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"` + AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"` + ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"` + ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"` + SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"` + EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"` + UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"` + ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"` + GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"` + IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"` + External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"` + EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"` + JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"` + CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"` + CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"` + CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"` + FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"` + Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"` + TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"` + WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"` + LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"` + OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"` + ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CriuOpts) Reset() { *m = CriuOpts{} } +func (m *CriuOpts) String() string { return proto.CompactTextString(m) } +func (*CriuOpts) ProtoMessage() {} +func (*CriuOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } const Default_CriuOpts_LogLevel int32 = 2 const Default_CriuOpts_CpuCap uint32 = 4294967295 +const Default_CriuOpts_GhostLimit uint32 = 1048576 func (m *CriuOpts) GetImagesDirFd() int32 { if m != nil && m.ImagesDirFd != nil { @@ -513,21 +636,134 @@ func (m *CriuOpts) GetUnixSkIno() []*UnixSk { return nil } -func (m *CriuOpts) GetManageCgroupsMode() uint32 { +func (m *CriuOpts) GetManageCgroupsMode() CriuCgMode { if m != nil && m.ManageCgroupsMode != nil { return *m.ManageCgroupsMode } + return CriuCgMode_IGNORE +} + +func (m *CriuOpts) GetGhostLimit() uint32 { + if m != nil && m.GhostLimit != nil { + return *m.GhostLimit + } + return Default_CriuOpts_GhostLimit +} + +func (m *CriuOpts) GetIrmapScanPaths() []string { + if m != nil { + return m.IrmapScanPaths + } + return nil +} + +func (m *CriuOpts) GetExternal() []string { + if m != nil { + return m.External + } + return nil +} + +func (m *CriuOpts) GetEmptyNs() uint32 { + if m != nil && m.EmptyNs != nil { + return *m.EmptyNs + } + return 0 +} + +func (m *CriuOpts) GetJoinNs() []*JoinNamespace { + if m != nil { + return m.JoinNs + } + return nil +} + +func (m *CriuOpts) GetCgroupProps() string { + if m != nil && m.CgroupProps != nil { + return *m.CgroupProps + } + return "" +} + +func (m *CriuOpts) GetCgroupPropsFile() string { + if m != nil && m.CgroupPropsFile != nil { + return *m.CgroupPropsFile + } + return "" +} + +func (m *CriuOpts) GetCgroupDumpController() []string { + if m != nil { + return m.CgroupDumpController + } + return nil +} + +func (m *CriuOpts) GetFreezeCgroup() string { + if m != nil && m.FreezeCgroup != nil { + return *m.FreezeCgroup + } + return "" +} + +func (m *CriuOpts) GetTimeout() uint32 { + if m != nil && m.Timeout != nil { + return *m.Timeout + } + return 0 +} + +func (m *CriuOpts) GetTcpSkipInFlight() bool { + if m != nil && m.TcpSkipInFlight != nil { + return *m.TcpSkipInFlight + } + return false +} + +func (m *CriuOpts) GetWeakSysctls() bool { + if m != nil && m.WeakSysctls != nil { + return *m.WeakSysctls + } + return false +} + +func (m *CriuOpts) GetLazyPages() bool { + if m != nil && m.LazyPages != nil { + return *m.LazyPages + } + return false +} + +func (m *CriuOpts) GetStatusFd() int32 { + if m != nil && m.StatusFd != nil { + return *m.StatusFd + } return 0 } +func (m *CriuOpts) GetOrphanPtsMaster() bool { + if m != nil && m.OrphanPtsMaster != nil { + return *m.OrphanPtsMaster + } + return false +} + +func (m *CriuOpts) GetConfigFile() string { + if m != nil && m.ConfigFile != nil { + return *m.ConfigFile + } + return "" +} + type CriuDumpResp struct { Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"` XXX_unrecognized []byte `json:"-"` } -func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} } -func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) } -func (*CriuDumpResp) ProtoMessage() {} +func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} } +func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) } +func (*CriuDumpResp) ProtoMessage() {} +func (*CriuDumpResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (m *CriuDumpResp) GetRestored() bool { if m != nil && m.Restored != nil { @@ -541,9 +777,10 @@ type CriuRestoreResp struct { XXX_unrecognized []byte `json:"-"` } -func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} } -func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) } -func (*CriuRestoreResp) ProtoMessage() {} +func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} } +func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) } +func (*CriuRestoreResp) ProtoMessage() {} +func (*CriuRestoreResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (m *CriuRestoreResp) GetPid() int32 { if m != nil && m.Pid != nil { @@ -558,9 +795,10 @@ type CriuNotify struct { XXX_unrecognized []byte `json:"-"` } -func (m *CriuNotify) Reset() { *m = CriuNotify{} } -func (m *CriuNotify) String() string { return proto.CompactTextString(m) } -func (*CriuNotify) ProtoMessage() {} +func (m *CriuNotify) Reset() { *m = CriuNotify{} } +func (m *CriuNotify) String() string { return proto.CompactTextString(m) } +func (*CriuNotify) ProtoMessage() {} +func (*CriuNotify) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } func (m *CriuNotify) GetScript() string { if m != nil && m.Script != nil { @@ -576,21 +814,55 @@ func (m *CriuNotify) GetPid() int32 { return 0 } +// +// List of features which can queried via +// CRIU_REQ_TYPE__FEATURE_CHECK +type CriuFeatures struct { + MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"` + LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CriuFeatures) Reset() { *m = CriuFeatures{} } +func (m *CriuFeatures) String() string { return proto.CompactTextString(m) } +func (*CriuFeatures) ProtoMessage() {} +func (*CriuFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *CriuFeatures) GetMemTrack() bool { + if m != nil && m.MemTrack != nil { + return *m.MemTrack + } + return false +} + +func (m *CriuFeatures) GetLazyPages() bool { + if m != nil && m.LazyPages != nil { + return *m.LazyPages + } + return false +} + type CriuReq struct { Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"` Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"` - NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success" json:"notify_success,omitempty"` + NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"` // // When set service won't close the connection but // will wait for more req-s to appear. Works not // for all request types. - KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open" json:"keep_open,omitempty"` - XXX_unrecognized []byte `json:"-"` + KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"` + // + // 'features' can be used to query which features + // are supported by the installed criu/kernel + // via RPC. + Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"` + XXX_unrecognized []byte `json:"-"` } -func (m *CriuReq) Reset() { *m = CriuReq{} } -func (m *CriuReq) String() string { return proto.CompactTextString(m) } -func (*CriuReq) ProtoMessage() {} +func (m *CriuReq) Reset() { *m = CriuReq{} } +func (m *CriuReq) String() string { return proto.CompactTextString(m) } +func (*CriuReq) ProtoMessage() {} +func (*CriuReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } func (m *CriuReq) GetType() CriuReqType { if m != nil && m.Type != nil { @@ -620,6 +892,13 @@ func (m *CriuReq) GetKeepOpen() bool { return false } +func (m *CriuReq) GetFeatures() *CriuFeatures { + if m != nil { + return m.Features + } + return nil +} + type CriuResp struct { Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"` Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"` @@ -627,13 +906,17 @@ type CriuResp struct { Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"` Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"` Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"` - CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno" json:"cr_errno,omitempty"` + CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"` + Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"` + CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"` + Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"` XXX_unrecognized []byte `json:"-"` } -func (m *CriuResp) Reset() { *m = CriuResp{} } -func (m *CriuResp) String() string { return proto.CompactTextString(m) } -func (*CriuResp) ProtoMessage() {} +func (m *CriuResp) Reset() { *m = CriuResp{} } +func (m *CriuResp) String() string { return proto.CompactTextString(m) } +func (*CriuResp) ProtoMessage() {} +func (*CriuResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } func (m *CriuResp) GetType() CriuReqType { if m != nil && m.Type != nil { @@ -684,6 +967,220 @@ func (m *CriuResp) GetCrErrno() int32 { return 0 } +func (m *CriuResp) GetFeatures() *CriuFeatures { + if m != nil { + return m.Features + } + return nil +} + +func (m *CriuResp) GetCrErrmsg() string { + if m != nil && m.CrErrmsg != nil { + return *m.CrErrmsg + } + return "" +} + +func (m *CriuResp) GetVersion() *CriuVersion { + if m != nil { + return m.Version + } + return nil +} + +// Answer for criu_req_type.VERSION requests +type CriuVersion struct { + Major *int32 `protobuf:"varint,1,req,name=major" json:"major,omitempty"` + Minor *int32 `protobuf:"varint,2,req,name=minor" json:"minor,omitempty"` + Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"` + Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"` + Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"` + Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CriuVersion) Reset() { *m = CriuVersion{} } +func (m *CriuVersion) String() string { return proto.CompactTextString(m) } +func (*CriuVersion) ProtoMessage() {} +func (*CriuVersion) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +func (m *CriuVersion) GetMajor() int32 { + if m != nil && m.Major != nil { + return *m.Major + } + return 0 +} + +func (m *CriuVersion) GetMinor() int32 { + if m != nil && m.Minor != nil { + return *m.Minor + } + return 0 +} + +func (m *CriuVersion) GetGitid() string { + if m != nil && m.Gitid != nil { + return *m.Gitid + } + return "" +} + +func (m *CriuVersion) GetSublevel() int32 { + if m != nil && m.Sublevel != nil { + return *m.Sublevel + } + return 0 +} + +func (m *CriuVersion) GetExtra() int32 { + if m != nil && m.Extra != nil { + return *m.Extra + } + return 0 +} + +func (m *CriuVersion) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + func init() { + proto.RegisterType((*CriuPageServerInfo)(nil), "criu_page_server_info") + proto.RegisterType((*CriuVethPair)(nil), "criu_veth_pair") + proto.RegisterType((*ExtMountMap)(nil), "ext_mount_map") + proto.RegisterType((*JoinNamespace)(nil), "join_namespace") + proto.RegisterType((*InheritFd)(nil), "inherit_fd") + proto.RegisterType((*CgroupRoot)(nil), "cgroup_root") + proto.RegisterType((*UnixSk)(nil), "unix_sk") + proto.RegisterType((*CriuOpts)(nil), "criu_opts") + proto.RegisterType((*CriuDumpResp)(nil), "criu_dump_resp") + proto.RegisterType((*CriuRestoreResp)(nil), "criu_restore_resp") + proto.RegisterType((*CriuNotify)(nil), "criu_notify") + proto.RegisterType((*CriuFeatures)(nil), "criu_features") + proto.RegisterType((*CriuReq)(nil), "criu_req") + proto.RegisterType((*CriuResp)(nil), "criu_resp") + proto.RegisterType((*CriuVersion)(nil), "criu_version") + proto.RegisterEnum("CriuCgMode", CriuCgMode_name, CriuCgMode_value) proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value) } + +func init() { proto.RegisterFile("criurpc.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 1795 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xdd, 0x72, 0x5b, 0xb7, + 0x11, 0x0e, 0x29, 0xf1, 0x0f, 0xfc, 0x31, 0x0d, 0xff, 0x04, 0x4e, 0x6a, 0x9b, 0xa1, 0xe3, 0x44, + 0x55, 0x5c, 0x36, 0x61, 0xec, 0xb8, 0xce, 0xb4, 0x17, 0x1e, 0x89, 0x74, 0xd9, 0x48, 0x22, 0x07, + 0x94, 0x3c, 0x93, 0x2b, 0xcc, 0xd1, 0x39, 0x20, 0x05, 0xf3, 0x1c, 0x9c, 0x53, 0x00, 0x54, 0x24, + 0x3f, 0x48, 0x9f, 0xa2, 0xcf, 0xd0, 0x57, 0xea, 0x65, 0x6f, 0x3b, 0xbb, 0x00, 0x65, 0x29, 0xc9, + 0xb4, 0xb9, 0xc3, 0x7e, 0xbb, 0x00, 0xf6, 0x7f, 0x97, 0xb4, 0x63, 0xa3, 0xd6, 0xa6, 0x88, 0x07, + 0x85, 0xc9, 0x5d, 0xde, 0x5f, 0x92, 0x7b, 0x00, 0x88, 0x22, 0x5a, 0x4a, 0x61, 0xa5, 0x39, 0x97, + 0x46, 0x28, 0xbd, 0xc8, 0x29, 0x23, 0xb5, 0x28, 0x49, 0x8c, 0xb4, 0x96, 0x95, 0x7a, 0xa5, 0x9d, + 0x06, 0xdf, 0x90, 0x94, 0x92, 0xed, 0x22, 0x37, 0x8e, 0x95, 0x7b, 0xa5, 0x9d, 0x0a, 0xc7, 0x33, + 0xed, 0x92, 0xad, 0x42, 0x25, 0x6c, 0x0b, 0x21, 0x38, 0xd2, 0x0e, 0x29, 0x2f, 0x12, 0xb6, 0x8d, + 0x40, 0x79, 0x91, 0xf4, 0xff, 0x4c, 0x3a, 0xf8, 0xd1, 0xb9, 0x74, 0x67, 0xa2, 0x88, 0x94, 0xa1, + 0x77, 0x48, 0x45, 0x2d, 0x84, 0xd2, 0xac, 0xd4, 0x2b, 0xef, 0x34, 0xf8, 0xb6, 0x5a, 0x4c, 0x34, + 0xbd, 0x47, 0xaa, 0x6a, 0x21, 0xf2, 0x35, 0x3c, 0x0f, 0x68, 0x45, 0x2d, 0xa6, 0x6b, 0xd7, 0xff, + 0x96, 0xb4, 0xe5, 0x85, 0x13, 0x59, 0xbe, 0xd6, 0x4e, 0x64, 0x51, 0x01, 0x1f, 0xae, 0xe4, 0x65, + 0xb8, 0x0a, 0x47, 0x40, 0xce, 0xa3, 0x34, 0x5c, 0x83, 0x63, 0xff, 0x2d, 0xe9, 0xbc, 0xcb, 0x95, + 0x16, 0x3a, 0xca, 0xa4, 0x2d, 0xa2, 0x58, 0x82, 0x52, 0xda, 0x86, 0x4b, 0x65, 0x6d, 0xe9, 0xc7, + 0xa4, 0xa6, 0xad, 0x58, 0xa8, 0x54, 0x86, 0x7b, 0x55, 0x6d, 0xc7, 0x2a, 0x95, 0xf4, 0x53, 0xd2, + 0x90, 0x17, 0xce, 0x44, 0x22, 0x2f, 0x1c, 0x5a, 0xd5, 0xe0, 0x75, 0x04, 0xa6, 0x85, 0xeb, 0x0f, + 0x08, 0x51, 0xfa, 0x4c, 0x1a, 0xe5, 0xc4, 0x22, 0xf9, 0x15, 0x4d, 0xbc, 0xe9, 0xf0, 0xa0, 0x37, + 0xfd, 0x05, 0x69, 0xc6, 0x4b, 0x93, 0xaf, 0x0b, 0x61, 0xf2, 0xdc, 0x81, 0xff, 0x62, 0x67, 0xd2, + 0xe0, 0x56, 0x3c, 0xa3, 0x4f, 0x23, 0x77, 0x16, 0xb4, 0xc0, 0x73, 0xff, 0x31, 0xa9, 0xad, 0xb5, + 0xba, 0x10, 0x76, 0x45, 0xef, 0x92, 0x8a, 0xd2, 0x79, 0x22, 0xf1, 0x97, 0x36, 0xf7, 0x44, 0xff, + 0xdf, 0x6d, 0xd2, 0x40, 0x9f, 0xe6, 0x85, 0xb3, 0xb4, 0x4f, 0xda, 0x2a, 0x8b, 0x96, 0xd2, 0x8a, + 0x44, 0x19, 0xb1, 0x48, 0x50, 0xb6, 0xc2, 0x9b, 0x1e, 0xdc, 0x57, 0x66, 0x9c, 0x6c, 0xc2, 0x54, + 0xfe, 0x10, 0xa6, 0x27, 0xa4, 0x9d, 0xca, 0xe8, 0x5c, 0x0a, 0xb3, 0xd6, 0x5a, 0xe9, 0x25, 0x1a, + 0x5b, 0xe7, 0x2d, 0x04, 0xb9, 0xc7, 0xe8, 0x23, 0xd2, 0x04, 0xef, 0x07, 0x6d, 0x30, 0xa8, 0x75, + 0x0e, 0x0e, 0x3a, 0xd1, 0xea, 0x62, 0xbe, 0xa2, 0x5f, 0x92, 0x5b, 0x2e, 0x2e, 0x84, 0xb4, 0x2e, + 0x3a, 0x4d, 0x95, 0x3d, 0x93, 0x09, 0xab, 0xa0, 0x4c, 0xc7, 0xc5, 0xc5, 0xe8, 0x03, 0x0a, 0x82, + 0xf2, 0x3c, 0xb2, 0xea, 0x5c, 0x8a, 0x44, 0x9e, 0xab, 0x58, 0x5a, 0x56, 0xf5, 0x82, 0x01, 0xde, + 0xf7, 0x28, 0xf8, 0xdf, 0x9e, 0xc9, 0x34, 0x15, 0xef, 0xf2, 0x53, 0x56, 0x43, 0x91, 0x3a, 0x02, + 0x7f, 0xcb, 0x4f, 0xe9, 0x43, 0x42, 0x20, 0x64, 0x22, 0xcd, 0xe3, 0x95, 0x65, 0x75, 0xaf, 0x0d, + 0x20, 0x07, 0x00, 0xd0, 0x47, 0xa4, 0x91, 0xe6, 0x4b, 0x91, 0xca, 0x73, 0x99, 0xb2, 0x06, 0x98, + 0xfa, 0x7d, 0x69, 0xc8, 0xeb, 0x69, 0xbe, 0x3c, 0x00, 0x88, 0x3e, 0x20, 0x70, 0xf6, 0x51, 0x27, + 0x3e, 0xb5, 0xd3, 0x7c, 0x89, 0x61, 0xff, 0x82, 0x94, 0x0b, 0xcb, 0x9a, 0xbd, 0xd2, 0x4e, 0x73, + 0x78, 0x7f, 0xf0, 0xab, 0x85, 0xc1, 0xcb, 0x85, 0xa5, 0x4f, 0x49, 0x47, 0xe7, 0x4e, 0x2d, 0x2e, + 0x85, 0x8d, 0x8d, 0x2a, 0x9c, 0x65, 0x2d, 0xd4, 0xa2, 0xed, 0xd1, 0xb9, 0x07, 0x21, 0xaa, 0x10, + 0x71, 0xd6, 0xf6, 0x91, 0xc6, 0xe8, 0x3f, 0x24, 0xa4, 0x88, 0x8c, 0xd4, 0x4e, 0xa8, 0x6c, 0xc9, + 0x3a, 0xc8, 0x69, 0x78, 0x64, 0x92, 0x2d, 0xc1, 0x70, 0x67, 0xa2, 0x78, 0x25, 0x32, 0x99, 0xb1, + 0x5b, 0xde, 0x70, 0x04, 0x0e, 0x65, 0x06, 0x77, 0xa3, 0xb5, 0xcb, 0x45, 0x22, 0x93, 0x75, 0xc1, + 0xba, 0xde, 0x70, 0x40, 0xf6, 0x01, 0x80, 0x30, 0xfd, 0x94, 0x9b, 0xd5, 0x26, 0xfe, 0xb7, 0x31, + 0xca, 0x0d, 0x80, 0x7c, 0xf4, 0x1f, 0x12, 0x92, 0x2a, 0xbd, 0x12, 0x46, 0x66, 0x51, 0xc1, 0xa8, + 0xbf, 0x0e, 0x08, 0x07, 0x80, 0x3e, 0x25, 0x15, 0x28, 0x4e, 0xcb, 0xee, 0xf4, 0xb6, 0x76, 0x9a, + 0xc3, 0x5b, 0x83, 0x9b, 0xf5, 0xca, 0x3d, 0x97, 0x3e, 0x21, 0xb5, 0xb8, 0x58, 0x8b, 0x38, 0x2a, + 0xd8, 0xdd, 0x5e, 0x69, 0xa7, 0xfd, 0x3d, 0x79, 0x3e, 0x7c, 0xf5, 0xfc, 0xd5, 0x77, 0x2f, 0x87, + 0xaf, 0x5e, 0xf0, 0x6a, 0x5c, 0xac, 0xf7, 0xa2, 0x82, 0x3e, 0x26, 0xcd, 0x45, 0x6e, 0x62, 0x29, + 0x94, 0x81, 0xbf, 0xee, 0xe1, 0x5f, 0x04, 0xa1, 0x09, 0x20, 0x10, 0x04, 0x79, 0x21, 0x63, 0x11, + 0x67, 0x09, 0xbb, 0xdf, 0xdb, 0x82, 0x20, 0x00, 0xbd, 0x97, 0x41, 0x92, 0xd4, 0xb0, 0xd6, 0xb5, + 0x63, 0x1f, 0xa3, 0x26, 0x9d, 0xc1, 0x8d, 0xda, 0xe7, 0x55, 0x79, 0xe1, 0x0e, 0xb5, 0x83, 0x28, + 0x64, 0x91, 0x86, 0xf8, 0xf8, 0xf2, 0xb2, 0x8c, 0xf9, 0x28, 0x78, 0x74, 0xcf, 0x83, 0xf4, 0x29, + 0xa9, 0xc5, 0x4b, 0x2c, 0x3d, 0xf6, 0x00, 0xdf, 0x6b, 0x0d, 0xae, 0x95, 0x23, 0xaf, 0xc6, 0x4b, + 0x0e, 0x81, 0x79, 0x4c, 0x9a, 0xc6, 0x3a, 0x61, 0xd5, 0x69, 0x0a, 0x75, 0xf0, 0x89, 0x57, 0xd9, + 0x58, 0x37, 0xf7, 0x08, 0xdd, 0xbd, 0x5e, 0xf6, 0xec, 0x53, 0x7c, 0xaa, 0x39, 0xf8, 0x00, 0xf1, + 0x46, 0x38, 0x8f, 0x13, 0xda, 0x23, 0x2d, 0x8c, 0xd4, 0xc6, 0x90, 0xdf, 0xf9, 0xd7, 0x00, 0x1b, + 0x79, 0xe5, 0x1f, 0xfb, 0x9a, 0xb2, 0x67, 0x91, 0x81, 0xef, 0x1e, 0x7a, 0x01, 0x79, 0xe1, 0xe6, + 0x1e, 0xd9, 0x08, 0x64, 0x91, 0x75, 0xd2, 0x58, 0xf6, 0xe8, 0x4a, 0xe0, 0xd0, 0x23, 0xe0, 0x42, + 0xbb, 0x52, 0x05, 0xbe, 0xff, 0xd8, 0xbb, 0x10, 0x68, 0x78, 0x1c, 0xda, 0x97, 0x8e, 0x4e, 0x53, + 0x29, 0x16, 0x96, 0xf5, 0x90, 0x57, 0xf7, 0xc0, 0xd8, 0xd2, 0x1d, 0xd2, 0x0c, 0x95, 0x2c, 0x94, + 0xce, 0xd9, 0x67, 0x68, 0x48, 0x7d, 0x10, 0x30, 0xde, 0x58, 0x63, 0x51, 0x4f, 0x74, 0x4e, 0xff, + 0x42, 0xee, 0xdc, 0x74, 0xb0, 0xc8, 0xa0, 0x09, 0xf5, 0x7b, 0xa5, 0x9d, 0xce, 0xb0, 0xed, 0xf3, + 0x23, 0x5e, 0x22, 0xc8, 0x6f, 0xdf, 0x70, 0xfa, 0x61, 0x9e, 0x48, 0xf8, 0x68, 0x79, 0x96, 0x5b, + 0x27, 0x52, 0x95, 0x29, 0xc7, 0x9e, 0x60, 0xb6, 0xd4, 0xbe, 0xf9, 0xfa, 0xf9, 0x9f, 0x5e, 0xbc, + 0xfc, 0x8e, 0x13, 0xe4, 0x1d, 0x00, 0x8b, 0xee, 0x90, 0x2e, 0x26, 0x8a, 0xb0, 0x71, 0xa4, 0x05, + 0x74, 0x3f, 0xcb, 0x3e, 0x47, 0xb5, 0x3b, 0x88, 0xcf, 0xe3, 0x48, 0xcf, 0x00, 0xa5, 0x9f, 0x40, + 0xde, 0x38, 0x69, 0x74, 0x94, 0xb2, 0xa7, 0xc1, 0xb0, 0x40, 0x63, 0x4e, 0x65, 0x85, 0xbb, 0x14, + 0xda, 0xb2, 0x2f, 0xe0, 0x33, 0x5e, 0x43, 0xfa, 0x08, 0x6c, 0xae, 0xf9, 0x51, 0x60, 0xd9, 0x97, + 0x21, 0xbb, 0x6f, 0x8e, 0x06, 0x5e, 0x05, 0xfa, 0xc8, 0xd2, 0xcf, 0x48, 0x2b, 0x64, 0x47, 0x61, + 0xf2, 0xc2, 0xb2, 0xdf, 0x63, 0x85, 0x86, 0x06, 0x3e, 0x03, 0x88, 0xee, 0x92, 0xdb, 0xd7, 0x45, + 0x7c, 0x27, 0xd9, 0x45, 0xb9, 0x5b, 0xd7, 0xe4, 0xb0, 0xa3, 0x3c, 0x27, 0xf7, 0x83, 0x6c, 0xb2, + 0xce, 0x0a, 0x11, 0xe7, 0xda, 0x99, 0x3c, 0x4d, 0xa5, 0x61, 0x5f, 0xa1, 0xf6, 0x77, 0x3d, 0x77, + 0x7f, 0x9d, 0x15, 0x7b, 0x57, 0x3c, 0xe8, 0xca, 0x0b, 0x23, 0xe5, 0xfb, 0x8d, 0xe3, 0xd9, 0x33, + 0x7c, 0xbd, 0xe5, 0x41, 0xef, 0x63, 0x98, 0xd0, 0x4e, 0x65, 0x12, 0x66, 0xe5, 0x1f, 0xbc, 0xb5, + 0x81, 0xa4, 0x5f, 0x11, 0x0a, 0xfd, 0x18, 0xb3, 0x43, 0x69, 0xb1, 0x48, 0xd5, 0xf2, 0xcc, 0xb1, + 0x01, 0x66, 0x10, 0x74, 0xea, 0xf9, 0x4a, 0x15, 0x13, 0x3d, 0x46, 0x18, 0x0c, 0xfe, 0x49, 0x46, + 0x2b, 0x61, 0x2f, 0x6d, 0xec, 0x52, 0xcb, 0xfe, 0x88, 0x62, 0x4d, 0xc0, 0xe6, 0x1e, 0xc2, 0xc6, + 0x11, 0xbd, 0xbf, 0xc4, 0x5e, 0x68, 0xd9, 0xd7, 0xa1, 0x71, 0x44, 0xef, 0x2f, 0x67, 0x00, 0x60, + 0xb3, 0x76, 0x91, 0x5b, 0x5b, 0xa8, 0x8b, 0x6f, 0xb0, 0xeb, 0xd4, 0x3d, 0x30, 0x4e, 0xc0, 0x59, + 0xb9, 0x29, 0xce, 0x20, 0xac, 0xce, 0x86, 0x6c, 0x66, 0x43, 0xaf, 0x8a, 0x67, 0xcc, 0x9c, 0xf5, + 0x29, 0x0d, 0x29, 0x1f, 0xe7, 0x7a, 0xa1, 0x42, 0x73, 0xfe, 0x16, 0x8d, 0x26, 0x1e, 0x02, 0x6f, + 0xf6, 0x9f, 0x85, 0x25, 0x02, 0x7d, 0x69, 0xa4, 0x2d, 0x20, 0x1f, 0x8c, 0xb4, 0x2e, 0x37, 0x32, + 0xc1, 0x81, 0x5a, 0xe7, 0x57, 0x74, 0xff, 0x29, 0xb9, 0x8d, 0xd2, 0x01, 0xf0, 0x17, 0xc2, 0x08, + 0xf4, 0xc3, 0x11, 0x8e, 0xfd, 0x97, 0xa4, 0x89, 0x62, 0xbe, 0x77, 0xd3, 0xfb, 0xa4, 0xea, 0x9b, + 0x7a, 0x18, 0xd0, 0x81, 0xfa, 0xe5, 0xec, 0xec, 0xff, 0xe0, 0x97, 0x29, 0xb1, 0x90, 0x91, 0x5b, + 0x1b, 0xef, 0x88, 0x4c, 0x66, 0x02, 0xfb, 0xf5, 0x46, 0x9b, 0x4c, 0x66, 0xc7, 0x40, 0xff, 0xcc, + 0x89, 0xe5, 0x9f, 0x39, 0xb1, 0xff, 0xaf, 0x12, 0xa9, 0x07, 0x6d, 0xff, 0x4e, 0xfb, 0x64, 0xdb, + 0x5d, 0x16, 0x7e, 0xdc, 0x77, 0x86, 0x9d, 0xc1, 0x86, 0x21, 0x00, 0xe5, 0xc8, 0xa3, 0x8f, 0xc8, + 0x36, 0xcc, 0x7d, 0x7c, 0xa9, 0x39, 0x24, 0x83, 0xab, 0x4d, 0x80, 0x23, 0x7e, 0x7d, 0x46, 0xad, + 0xe3, 0x18, 0xf6, 0xb8, 0xad, 0x1b, 0x33, 0xca, 0x83, 0xa0, 0xf3, 0x4a, 0xca, 0x42, 0xe4, 0x85, + 0xd4, 0x61, 0xb2, 0xd7, 0x01, 0x98, 0x16, 0x52, 0xd3, 0x5d, 0x52, 0xdf, 0x18, 0x87, 0x13, 0xbd, + 0xb9, 0xd1, 0x65, 0x83, 0xf2, 0x2b, 0x7e, 0xff, 0x3f, 0xe5, 0xb0, 0x8d, 0xa0, 0x9b, 0x7f, 0x8b, + 0x05, 0x8c, 0xd4, 0x36, 0xaa, 0xc1, 0xde, 0x53, 0xe7, 0x1b, 0x92, 0x3e, 0x21, 0xdb, 0x10, 0x62, + 0xd4, 0xf8, 0x6a, 0x12, 0x5d, 0x05, 0x9d, 0x23, 0x93, 0x3e, 0x23, 0xb5, 0x10, 0x59, 0xd4, 0xbb, + 0x39, 0xa4, 0x83, 0x5f, 0x84, 0x9b, 0x6f, 0x44, 0xe8, 0xe7, 0xa4, 0xea, 0x0d, 0x0f, 0x86, 0xb4, + 0x06, 0xd7, 0x82, 0xce, 0x03, 0x2f, 0x2c, 0x00, 0xd5, 0xff, 0xbb, 0x00, 0x3c, 0x80, 0x60, 0x09, + 0x69, 0x8c, 0xce, 0x71, 0x3d, 0xa9, 0xf0, 0x5a, 0x6c, 0x46, 0x40, 0xde, 0xf0, 0x59, 0xfd, 0x7f, + 0xfb, 0x0c, 0x9c, 0xef, 0x9f, 0xc9, 0xec, 0x12, 0x57, 0x95, 0x06, 0xaf, 0xe3, 0x3b, 0x99, 0x5d, + 0xc2, 0x1c, 0x3c, 0x97, 0xc6, 0xaa, 0x5c, 0xe3, 0x9a, 0xd2, 0xdc, 0x74, 0xdc, 0x00, 0xf2, 0x0d, + 0xb7, 0xff, 0x8f, 0x12, 0x69, 0x5d, 0xe7, 0xc0, 0xba, 0x98, 0x45, 0xef, 0x72, 0x13, 0xb2, 0xdc, + 0x13, 0x88, 0x2a, 0x9d, 0x9b, 0xb0, 0x99, 0x7a, 0x02, 0xd0, 0xa5, 0x72, 0x61, 0x77, 0x6f, 0x70, + 0x4f, 0x40, 0x59, 0xd9, 0xf5, 0xa9, 0x5f, 0xa1, 0xb6, 0x43, 0x45, 0x07, 0x1a, 0x6e, 0xe0, 0x2a, + 0x8c, 0x8e, 0xac, 0x70, 0x4f, 0xc0, 0xae, 0x03, 0xcd, 0x14, 0x7d, 0xd7, 0xe0, 0x78, 0xde, 0x15, + 0x41, 0xaf, 0x30, 0x23, 0x28, 0x21, 0xd5, 0xc9, 0x9b, 0xa3, 0x29, 0x1f, 0x75, 0x3f, 0xa2, 0x4d, + 0x52, 0xdb, 0x7b, 0x23, 0x8e, 0xa6, 0x47, 0xa3, 0x6e, 0x89, 0x36, 0x48, 0x65, 0xc6, 0xa7, 0xb3, + 0x79, 0xb7, 0x4c, 0xeb, 0x64, 0x7b, 0x3e, 0x1d, 0x1f, 0x77, 0xb7, 0xe0, 0x34, 0x3e, 0x39, 0x38, + 0xe8, 0x6e, 0xc3, 0xbd, 0xf9, 0x31, 0x9f, 0xec, 0x1d, 0x77, 0x2b, 0x70, 0x6f, 0x7f, 0x34, 0x7e, + 0x7d, 0x72, 0x70, 0xdc, 0xad, 0xee, 0xfe, 0xb3, 0x14, 0x4a, 0x70, 0x93, 0x59, 0xf0, 0xd2, 0xe8, + 0x70, 0x76, 0xfc, 0x63, 0xf7, 0x23, 0xb8, 0xbf, 0x7f, 0x72, 0x38, 0xeb, 0x96, 0xe0, 0x0e, 0x1f, + 0xcd, 0x8f, 0xe1, 0xe3, 0x32, 0x48, 0xec, 0xfd, 0x75, 0xb4, 0xf7, 0x43, 0x77, 0x8b, 0xb6, 0x48, + 0x7d, 0xc6, 0x47, 0x02, 0xa5, 0xb6, 0xe9, 0x2d, 0xd2, 0x9c, 0xbd, 0x7e, 0x33, 0x12, 0xf3, 0x11, + 0x7f, 0x3b, 0xe2, 0xdd, 0x0a, 0x7c, 0x7b, 0x34, 0x3d, 0x9e, 0x8c, 0x7f, 0xec, 0x56, 0x69, 0x97, + 0xb4, 0xf6, 0x66, 0x27, 0x93, 0xa3, 0xf1, 0xd4, 0x8b, 0xd7, 0xe8, 0x6d, 0xd2, 0xde, 0x20, 0xfe, + 0xbd, 0x3a, 0x40, 0xe3, 0xd1, 0xeb, 0xe3, 0x13, 0x3e, 0x0a, 0x50, 0x03, 0xbe, 0x7e, 0x3b, 0xe2, + 0xf3, 0xc9, 0xf4, 0xa8, 0x4b, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xc2, 0x38, 0x55, 0x41, 0x7c, + 0x0d, 0x00, 0x00, +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go similarity index 58% rename from vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go rename to vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go index c02b73e3e6a39939a4bb6f82869bef270795e925..5e2ab0581e2fb0dbd4dd0a4a14b6cb4a09da3395 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go @@ -1,16 +1,14 @@ -// +build linux freebsd - package devices import ( "errors" - "fmt" "io/ioutil" "os" "path/filepath" - "syscall" "github.com/opencontainers/runc/libcontainer/configs" + + "golang.org/x/sys/unix" ) var ( @@ -19,45 +17,46 @@ var ( // Testing dependencies var ( - osLstat = os.Lstat + unixLstat = unix.Lstat ioutilReadDir = ioutil.ReadDir ) -// Given the path to a device and it's cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct. +// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct. func DeviceFromPath(path, permissions string) (*configs.Device, error) { - fileInfo, err := osLstat(path) + var stat unix.Stat_t + err := unixLstat(path, &stat) if err != nil { return nil, err } + var ( - devType rune - mode = fileInfo.Mode() - fileModePermissionBits = os.FileMode.Perm(mode) + devNumber = uint64(stat.Rdev) + major = unix.Major(devNumber) + minor = unix.Minor(devNumber) ) - switch { - case mode&os.ModeDevice == 0: + if major == 0 { return nil, ErrNotADevice - case mode&os.ModeCharDevice != 0: - fileModePermissionBits |= syscall.S_IFCHR - devType = 'c' - default: - fileModePermissionBits |= syscall.S_IFBLK - devType = 'b' } - stat_t, ok := fileInfo.Sys().(*syscall.Stat_t) - if !ok { - return nil, fmt.Errorf("cannot determine the device number for device %s", path) + + var ( + devType rune + mode = stat.Mode + ) + switch { + case mode&unix.S_IFBLK == unix.S_IFBLK: + devType = 'b' + case mode&unix.S_IFCHR == unix.S_IFCHR: + devType = 'c' } - devNumber := int(stat_t.Rdev) return &configs.Device{ Type: devType, Path: path, - Major: Major(devNumber), - Minor: Minor(devNumber), + Major: int64(major), + Minor: int64(minor), Permissions: permissions, - FileMode: fileModePermissionBits, - Uid: stat_t.Uid, - Gid: stat_t.Gid, + FileMode: os.FileMode(mode), + Uid: stat.Uid, + Gid: stat.Gid, }, nil } @@ -75,7 +74,8 @@ func getDevices(path string) ([]*configs.Device, error) { switch { case f.IsDir(): switch f.Name() { - case "pts", "shm", "fd", "mqueue": + // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 + case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts": continue default: sub, err := getDevices(filepath.Join(path, f.Name())) @@ -94,6 +94,9 @@ func getDevices(path string) ([]*configs.Device, error) { if err == ErrNotADevice { continue } + if os.IsNotExist(err) { + continue + } return nil, err } out = append(out, device) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_test.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_test.go index 50ea78bc3f58115fa25f5e3bdee40ea9591e7e7d..0afa9d9212dc3bdf3a6a9692c22e71404c3427c2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_test.go @@ -1,19 +1,19 @@ -// +build linux freebsd - package devices import ( "errors" "os" "testing" + + "golang.org/x/sys/unix" ) func TestDeviceFromPathLstatFailure(t *testing.T) { testError := errors.New("test error") - // Override os.Lstat to inject error. - osLstat = func(path string) (os.FileInfo, error) { - return nil, testError + // Override unix.Lstat to inject error. + unixLstat = func(path string, stat *unix.Stat_t) error { + return testError } _, err := DeviceFromPath("", "") diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go deleted file mode 100644 index 1e84033daff8297f2e183a1dad5dace4094f3c2c..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build windows - -package devices diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/number.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/number.go deleted file mode 100644 index 885b6e5dd9363d5a746b6753bee90e394d81bfbd..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/number.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build linux freebsd - -package devices - -/* - -This code provides support for manipulating linux device numbers. It should be replaced by normal syscall functions once http://code.google.com/p/go/issues/detail?id=8106 is solved. - -You can read what they are here: - - - http://www.makelinux.net/ldd3/chp-3-sect-2 - - http://www.linux-tutorial.info/modules.php?name=MContent&pageid=94 - -Note! These are NOT the same as the MAJOR(dev_t device);, MINOR(dev_t device); and MKDEV(int major, int minor); functions as defined in <linux/kdev_t.h> as the representation of device numbers used by go is different than the one used internally to the kernel! - https://github.com/torvalds/linux/blob/master/include/linux/kdev_t.h#L9 - -*/ - -func Major(devNumber int) int64 { - return int64((devNumber >> 8) & 0xfff) -} - -func Minor(devNumber int) int64 { - return int64((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00)) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/error.go b/vendor/github.com/opencontainers/runc/libcontainer/error.go index b50aaae84ed51828044402cb6bf67a1e293f1b48..21a3789ba18de06dfb69cfe04c19d8e37890f697 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/error.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/error.go @@ -2,7 +2,7 @@ package libcontainer import "io" -// API error code type. +// ErrorCode is the API error code type. type ErrorCode int // API error codes. @@ -56,13 +56,13 @@ func (c ErrorCode) String() string { } } -// API Error type. +// Error is the API error type. type Error interface { error - // Returns a verbose string including the error message - // and a representation of the stack trace suitable for - // printing. + // Returns an error if it failed to write the detail of the Error to w. + // The detail of the Error may include the error message and a + // representation of the stack trace. Detail(w io.Writer) error // Returns the error code for this error. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/error_test.go b/vendor/github.com/opencontainers/runc/libcontainer/error_test.go index 4bf4c9f5d492af9177cd614aae3c896e2d6dcb80..36841ad83c89220b0f3b33c4d95aa7b93bdcdac5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/error_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/error_test.go @@ -4,12 +4,17 @@ import "testing" func TestErrorCode(t *testing.T) { codes := map[ErrorCode]string{ - IdInUse: "Id already in use", - InvalidIdFormat: "Invalid format", - ContainerPaused: "Container paused", - ConfigInvalid: "Invalid configuration", - SystemError: "System error", - ContainerNotExists: "Container does not exist", + IdInUse: "Id already in use", + InvalidIdFormat: "Invalid format", + ContainerPaused: "Container paused", + ConfigInvalid: "Invalid configuration", + SystemError: "System error", + ContainerNotExists: "Container does not exist", + ContainerNotStopped: "Container is not stopped", + ContainerNotRunning: "Container is not running", + ConsoleExists: "Console exists for process", + ContainerNotPaused: "Container is not paused", + NoProcessOps: "No process operations", } for code, expected := range codes { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory.go b/vendor/github.com/opencontainers/runc/libcontainer/factory.go index f0ccb52e39d308de22ef47f3a67c56f6e9de68fa..0986cd77e3fe05fa6ec2534d12bbb57a688ae78d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory.go @@ -10,7 +10,7 @@ type Factory interface { // between 1 and 1024 characters, inclusive. // // The id must not already be in use by an existing container. Containers created using - // a factory with the same path (and file system) must have distinct ids. + // a factory with the same path (and filesystem) must have distinct ids. // // Returns the new container with a running process. // @@ -28,7 +28,6 @@ type Factory interface { // // errors: // Path does not exist - // Container is stopped // System error Load(id string) (Container, error) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go index eb327be78933d205256f9bbf18600da07943fec8..e35957c31482c8a84c9c0d485cdcb9c661edac21 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -6,57 +6,43 @@ import ( "encoding/json" "fmt" "os" - "os/exec" "path/filepath" "regexp" + "runtime/debug" "strconv" - "syscall" - "github.com/docker/docker/pkg/mount" + "github.com/cyphar/filepath-securejoin" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs/validate" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/mount" "github.com/opencontainers/runc/libcontainer/utils" + + "golang.org/x/sys/unix" ) const ( - stateFilename = "state.json" + stateFilename = "state.json" + execFifoFilename = "exec.fifo" ) -var ( - idRegex = regexp.MustCompile(`^[\w_-]+$`) - maxIdLen = 1024 -) +var idRegex = regexp.MustCompile(`^[\w+-\.]+$`) // InitArgs returns an options func to configure a LinuxFactory with the -// provided init arguments. +// provided init binary path and arguments. func InitArgs(args ...string) func(*LinuxFactory) error { - return func(l *LinuxFactory) error { - name := args[0] - if filepath.Base(name) == name { - if lp, err := exec.LookPath(name); err == nil { - name = lp + return func(l *LinuxFactory) (err error) { + if len(args) > 0 { + // Resolve relative paths to ensure that its available + // after directory changes. + if args[0], err = filepath.Abs(args[0]); err != nil { + return newGenericError(err, ConfigInvalid) } - } else { - abs, err := filepath.Abs(name) - if err != nil { - return err - } - name = abs } - l.InitPath = "/proc/self/exe" - l.InitArgs = append([]string{name}, args[1:]...) - return nil - } -} -// InitPath returns an options func to configure a LinuxFactory with the -// provided absolute path to the init binary and arguements. -func InitPath(path string, args ...string) func(*LinuxFactory) error { - return func(l *LinuxFactory) error { - l.InitPath = path l.InitArgs = args return nil } @@ -74,9 +60,9 @@ func SystemdCgroups(l *LinuxFactory) error { return nil } -// Cgroupfs is an options func to configure a LinuxFactory to return -// containers that use the native cgroups filesystem implementation to -// create and manage cgroups. +// Cgroupfs is an options func to configure a LinuxFactory to return containers +// that use the native cgroups filesystem implementation to create and manage +// cgroups. func Cgroupfs(l *LinuxFactory) error { l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { return &fs.Manager{ @@ -87,6 +73,37 @@ func Cgroupfs(l *LinuxFactory) error { return nil } +// RootlessCgroupfs is an options func to configure a LinuxFactory to return +// containers that use the native cgroups filesystem implementation to create +// and manage cgroups. The difference between RootlessCgroupfs and Cgroupfs is +// that RootlessCgroupfs can transparently handle permission errors that occur +// during rootless container (including euid=0 in userns) setup (while still allowing cgroup usage if +// they've been set up properly). +func RootlessCgroupfs(l *LinuxFactory) error { + l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return &fs.Manager{ + Cgroups: config, + Rootless: true, + Paths: paths, + } + } + return nil +} + +// IntelRdtfs is an options func to configure a LinuxFactory to return +// containers that use the Intel RDT "resource control" filesystem to +// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth). +func IntelRdtFs(l *LinuxFactory) error { + l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager { + return &intelrdt.IntelRdtManager{ + Config: config, + Id: id, + Path: path, + } + } + return nil +} + // TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs. func TmpfsRoot(l *LinuxFactory) error { mounted, err := mount.Mounted(l.Root) @@ -94,13 +111,22 @@ func TmpfsRoot(l *LinuxFactory) error { return err } if !mounted { - if err := syscall.Mount("tmpfs", l.Root, "tmpfs", 0, ""); err != nil { + if err := unix.Mount("tmpfs", l.Root, "tmpfs", 0, ""); err != nil { return err } } return nil } +// CriuPath returns an option func to configure a LinuxFactory with the +// provided criupath +func CriuPath(criupath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.CriuPath = criupath + return nil + } +} + // New returns a linux based container factory based in the root directory and // configures the factory with the provided option funcs. func New(root string, options ...func(*LinuxFactory) error) (Factory, error) { @@ -111,12 +137,16 @@ func New(root string, options ...func(*LinuxFactory) error) (Factory, error) { } l := &LinuxFactory{ Root: root, + InitPath: "/proc/self/exe", + InitArgs: []string{os.Args[0], "init"}, Validator: validate.New(), CriuPath: "criu", } - InitArgs(os.Args[0], "init")(l) Cgroupfs(l) for _, opt := range options { + if opt == nil { + continue + } if err := opt(l); err != nil { return nil, err } @@ -129,7 +159,8 @@ type LinuxFactory struct { // Root directory for the factory to store state. Root string - // InitPath is the absolute path to the init binary. + // InitPath is the path for calling the init responsibilities for spawning + // a container. InitPath string // InitArgs are arguments for calling the init responsibilities for spawning @@ -140,11 +171,19 @@ type LinuxFactory struct { // containers. CriuPath string + // New{u,g}uidmapPath is the path to the binaries used for mapping with + // rootless containers. + NewuidmapPath string + NewgidmapPath string + // Validator provides validation to container configurations. Validator validate.Validator // NewCgroupsManager returns an initialized cgroups manager for a single container. NewCgroupsManager func(config *configs.Cgroup, paths map[string]string) cgroups.Manager + + // NewIntelRdtManager returns an initialized Intel RDT manager for a single container. + NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager } func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) { @@ -157,13 +196,19 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err if err := l.Validator.Validate(config); err != nil { return nil, newGenericError(err, ConfigInvalid) } - containerRoot := filepath.Join(l.Root, id) + containerRoot, err := securejoin.SecureJoin(l.Root, id) + if err != nil { + return nil, err + } if _, err := os.Stat(containerRoot); err == nil { return nil, newGenericError(fmt.Errorf("container with id exists: %v", id), IdInUse) } else if !os.IsNotExist(err) { return nil, newGenericError(err, SystemError) } - if err := os.MkdirAll(containerRoot, 0700); err != nil { + if err := os.MkdirAll(containerRoot, 0711); err != nil { + return nil, newGenericError(err, SystemError) + } + if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil { return nil, newGenericError(err, SystemError) } c := &linuxContainer{ @@ -173,8 +218,13 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err initPath: l.InitPath, initArgs: l.InitArgs, criuPath: l.CriuPath, + newuidmapPath: l.NewuidmapPath, + newgidmapPath: l.NewgidmapPath, cgroupManager: l.NewCgroupsManager(config.Cgroups, nil), } + if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() { + c.intelRdtManager = l.NewIntelRdtManager(config, id, "") + } c.state = &stoppedState{c: c} return c, nil } @@ -183,8 +233,15 @@ func (l *LinuxFactory) Load(id string) (Container, error) { if l.Root == "" { return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid) } - containerRoot := filepath.Join(l.Root, id) - state, err := l.loadState(containerRoot) + //when load, we need to check id is valid or not. + if err := l.validateID(id); err != nil { + return nil, err + } + containerRoot, err := securejoin.SecureJoin(l.Root, id) + if err != nil { + return nil, err + } + state, err := l.loadState(containerRoot, id) if err != nil { return nil, err } @@ -194,20 +251,26 @@ func (l *LinuxFactory) Load(id string) (Container, error) { fds: state.ExternalDescriptors, } c := &linuxContainer{ - initProcess: r, - id: id, - config: &state.Config, - initPath: l.InitPath, - initArgs: l.InitArgs, - criuPath: l.CriuPath, - cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths), - root: containerRoot, - created: state.Created, + initProcess: r, + initProcessStartTime: state.InitProcessStartTime, + id: id, + config: &state.Config, + initPath: l.InitPath, + initArgs: l.InitArgs, + criuPath: l.CriuPath, + newuidmapPath: l.NewuidmapPath, + newgidmapPath: l.NewgidmapPath, + cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths), + root: containerRoot, + created: state.Created, } - c.state = &createdState{c: c, s: Created} + c.state = &loadedState{c: c} if err := c.refreshState(); err != nil { return nil, err } + if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() { + c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath) + } return c, nil } @@ -218,56 +281,83 @@ func (l *LinuxFactory) Type() string { // StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state // This is a low level implementation detail of the reexec and should not be consumed externally func (l *LinuxFactory) StartInitialization() (err error) { - fdStr := os.Getenv("_LIBCONTAINER_INITPIPE") - pipefd, err := strconv.Atoi(fdStr) + var ( + pipefd, fifofd int + consoleSocket *os.File + envInitPipe = os.Getenv("_LIBCONTAINER_INITPIPE") + envFifoFd = os.Getenv("_LIBCONTAINER_FIFOFD") + envConsole = os.Getenv("_LIBCONTAINER_CONSOLE") + ) + + // Get the INITPIPE. + pipefd, err = strconv.Atoi(envInitPipe) if err != nil { - return fmt.Errorf("error converting env var _LIBCONTAINER_INITPIPE(%q) to an int: %s", fdStr, err) + return fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE=%s to int: %s", envInitPipe, err) } + var ( pipe = os.NewFile(uintptr(pipefd), "pipe") it = initType(os.Getenv("_LIBCONTAINER_INITTYPE")) ) defer pipe.Close() + + // Only init processes have FIFOFD. + fifofd = -1 + if it == initStandard { + if fifofd, err = strconv.Atoi(envFifoFd); err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD=%s to int: %s", envFifoFd, err) + } + } + + if envConsole != "" { + console, err := strconv.Atoi(envConsole) + if err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE=%s to int: %s", envConsole, err) + } + consoleSocket = os.NewFile(uintptr(console), "console-socket") + defer consoleSocket.Close() + } + // clear the current process's environment to clean any libcontainer // specific env vars. os.Clearenv() - i, err := newContainerInit(it, pipe) - if err != nil { - l.sendError(nil, pipe, err) - return err - } - if err := i.Init(); err != nil { - if !isExecError(err) { - l.sendError(i, pipe, err) + + defer func() { + // We have an error during the initialization of the container's init, + // send it back to the parent process in the form of an initError. + if werr := utils.WriteJSON(pipe, syncT{procError}); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + if werr := utils.WriteJSON(pipe, newSystemError(err)); werr != nil { + fmt.Fprintln(os.Stderr, err) + return } + }() + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("panic from initialization: %v, %v", e, string(debug.Stack())) + } + }() + + i, err := newContainerInit(it, pipe, consoleSocket, fifofd) + if err != nil { return err } - return nil -} -func (l *LinuxFactory) sendError(i initer, pipe *os.File, err error) { - // We have an error during the initialization of the container's init, - // send it back to the parent process in the form of an initError. - // If container's init successed, syscall.Exec will not return, hence - // this defer function will never be called. - if i != nil { - if _, ok := i.(*linuxStandardInit); ok { - // Synchronisation only necessary for standard init. - if err := utils.WriteJSON(pipe, syncT{procError}); err != nil { - panic(err) - } - } - } - if err := utils.WriteJSON(pipe, newSystemError(err)); err != nil { - panic(err) - } + // If Init succeeds, syscall.Exec will not return, hence none of the defers will be called. + return i.Init() } -func (l *LinuxFactory) loadState(root string) (*State, error) { - f, err := os.Open(filepath.Join(root, stateFilename)) +func (l *LinuxFactory) loadState(root, id string) (*State, error) { + stateFilePath, err := securejoin.SecureJoin(root, stateFilename) + if err != nil { + return nil, err + } + f, err := os.Open(stateFilePath) if err != nil { if os.IsNotExist(err) { - return nil, newGenericError(err, ContainerNotExists) + return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists) } return nil, newGenericError(err, SystemError) } @@ -280,16 +370,27 @@ func (l *LinuxFactory) loadState(root string) (*State, error) { } func (l *LinuxFactory) validateID(id string) error { - if !idRegex.MatchString(id) { - return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) - } - if len(id) > maxIdLen { + if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) { return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) } + return nil } -func isExecError(err error) bool { - _, ok := err.(*exec.Error) - return ok +// NewuidmapPath returns an option func to configure a LinuxFactory with the +// provided .. +func NewuidmapPath(newuidmapPath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.NewuidmapPath = newuidmapPath + return nil + } +} + +// NewgidmapPath returns an option func to configure a LinuxFactory with the +// provided .. +func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.NewgidmapPath = newgidmapPath + return nil + } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux_test.go index ea3b5132d77bbd37e39970d0a27547e3ecd5bff4..8d0ca8a4743893c7a52b900811767b9490a637bf 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux_test.go @@ -7,12 +7,14 @@ import ( "os" "path/filepath" "reflect" - "syscall" "testing" - "github.com/docker/docker/pkg/mount" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/mount" "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + + "golang.org/x/sys/unix" ) func newTestRoot() (string, error) { @@ -49,6 +51,32 @@ func TestFactoryNew(t *testing.T) { } } +func TestFactoryNewIntelRdt(t *testing.T) { + root, rerr := newTestRoot() + if rerr != nil { + t.Fatal(rerr) + } + defer os.RemoveAll(root) + factory, err := New(root, Cgroupfs, IntelRdtFs) + if err != nil { + t.Fatal(err) + } + if factory == nil { + t.Fatal("factory should not be nil") + } + lfactory, ok := factory.(*LinuxFactory) + if !ok { + t.Fatal("expected linux factory returned on linux based systems") + } + if lfactory.Root != root { + t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root) + } + + if factory.Type() != "libcontainer" { + t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer") + } +} + func TestFactoryNewTmpfs(t *testing.T) { root, rerr := newTestRoot() if rerr != nil { @@ -99,7 +127,7 @@ func TestFactoryNewTmpfs(t *testing.T) { if !found { t.Fatalf("Factory Root is not listed in mounts list") } - defer syscall.Unmount(root, syscall.MNT_DETACH) + defer unix.Unmount(root, unix.MNT_DETACH) } func TestFactoryLoadNotExists(t *testing.T) { @@ -163,7 +191,7 @@ func TestFactoryLoadContainer(t *testing.T) { if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil { t.Fatal(err) } - factory, err := New(root, Cgroupfs) + factory, err := New(root, Cgroupfs, IntelRdtFs) if err != nil { t.Fatal(err) } @@ -202,6 +230,6 @@ func marshal(path string, v interface{}) error { type unserializableHook struct{} -func (unserializableHook) Run(configs.HookState) error { +func (unserializableHook) Run(*specs.State) error { return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go b/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go index 93bb7570db20c4b359ec26a0213dabf32cf2f2ca..6e7de2fe7e0715a8309e4c9a8be0687e40cb9912 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go @@ -9,20 +9,6 @@ import ( "github.com/opencontainers/runc/libcontainer/stacktrace" ) -type syncType uint8 - -const ( - procReady syncType = iota - procError - procRun - procHooks - procResume -) - -type syncT struct { - Type syncType `json:"type"` -} - var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}} Code: {{.ECode}} {{if .Message }} @@ -52,14 +38,27 @@ func newGenericError(err error, c ErrorCode) Error { } func newSystemError(err error) Error { - if le, ok := err.(Error); ok { - return le - } + return createSystemError(err, "") +} + +func newSystemErrorWithCausef(err error, cause string, v ...interface{}) Error { + return createSystemError(err, fmt.Sprintf(cause, v...)) +} + +func newSystemErrorWithCause(err error, cause string) Error { + return createSystemError(err, cause) +} + +// createSystemError creates the specified error with the correct number of +// stack frames skipped. This is only to be called by the other functions for +// formatting the error. +func createSystemError(err error, cause string) Error { gerr := &genericError{ Timestamp: time.Now(), Err: err, ECode: SystemError, - Stack: stacktrace.Capture(1), + Cause: cause, + Stack: stacktrace.Capture(2), } if err != nil { gerr.Message = err.Error() @@ -71,12 +70,17 @@ type genericError struct { Timestamp time.Time ECode ErrorCode Err error `json:"-"` + Cause string Message string Stack stacktrace.Stacktrace } func (e *genericError) Error() string { - return fmt.Sprintf("[%d] %s: %s", e.ECode, e.ECode, e.Message) + if e.Cause == "" { + return e.Message + } + frame := e.Stack.Frames[0] + return fmt.Sprintf("%s:%d: %s caused %q", frame.File, frame.Line, e.Cause, e.Message) } func (e *genericError) Code() ErrorCode { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/generic_error_test.go b/vendor/github.com/opencontainers/runc/libcontainer/generic_error_test.go index 292d2a36bdcebdbfd433aa41ab9a4b89acee4d80..8fbdd4d381f95943606ee0a2555f10573a91316d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/generic_error_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/generic_error_test.go @@ -12,3 +12,38 @@ func TestErrorDetail(t *testing.T) { t.Fatal(derr) } } + +func TestErrorWithCode(t *testing.T) { + err := newGenericError(fmt.Errorf("test error"), SystemError) + if code := err.Code(); code != SystemError { + t.Fatalf("expected err code %q but %q", SystemError, code) + } +} + +func TestErrorWithError(t *testing.T) { + cc := []struct { + errmsg string + cause string + }{ + { + errmsg: "test error", + }, + { + errmsg: "test error", + cause: "test", + }, + } + + for _, v := range cc { + err := newSystemErrorWithCause(fmt.Errorf(v.errmsg), v.cause) + + msg := err.Error() + if v.cause == "" && msg != v.errmsg { + t.Fatalf("expected err(%q) equal errmsg(%q)", msg, v.errmsg) + } + if v.cause != "" && msg == v.errmsg { + t.Fatalf("unexpected err(%q) equal errmsg(%q)", msg, v.errmsg) + } + + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go index d54a2d1e4c0678ae8bfe633eaccfd157c8b1c4a0..cd7ff67a7023b423469236e3d812cf3ea511e502 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -9,16 +9,20 @@ import ( "io/ioutil" "net" "os" - "strconv" "strings" - "syscall" + "syscall" // only for Errno + "unsafe" - "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + + "github.com/containerd/console" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/user" "github.com/opencontainers/runc/libcontainer/utils" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" ) @@ -30,7 +34,8 @@ const ( ) type pid struct { - Pid int `json:"pid"` + Pid int `json:"pid"` + PidFirstChild int `json:"pid_first"` } // network is an internal struct used to setup container networks. @@ -44,27 +49,32 @@ type network struct { // initConfig is used for transferring parameters from Exec() to Init() type initConfig struct { - Args []string `json:"args"` - Env []string `json:"env"` - Cwd string `json:"cwd"` - Capabilities []string `json:"capabilities"` - ProcessLabel string `json:"process_label"` - AppArmorProfile string `json:"apparmor_profile"` - NoNewPrivileges bool `json:"no_new_privileges"` - User string `json:"user"` - Config *configs.Config `json:"config"` - Console string `json:"console"` - Networks []*network `json:"network"` - PassedFilesCount int `json:"passed_files_count"` - ContainerId string `json:"containerid"` - Rlimits []configs.Rlimit `json:"rlimits"` + Args []string `json:"args"` + Env []string `json:"env"` + Cwd string `json:"cwd"` + Capabilities *configs.Capabilities `json:"capabilities"` + ProcessLabel string `json:"process_label"` + AppArmorProfile string `json:"apparmor_profile"` + NoNewPrivileges bool `json:"no_new_privileges"` + User string `json:"user"` + AdditionalGroups []string `json:"additional_groups"` + Config *configs.Config `json:"config"` + Networks []*network `json:"network"` + PassedFilesCount int `json:"passed_files_count"` + ContainerId string `json:"containerid"` + Rlimits []configs.Rlimit `json:"rlimits"` + CreateConsole bool `json:"create_console"` + ConsoleWidth uint16 `json:"console_width"` + ConsoleHeight uint16 `json:"console_height"` + RootlessEUID bool `json:"rootless_euid,omitempty"` + RootlessCgroups bool `json:"rootless_cgroups,omitempty"` } type initer interface { Init() error } -func newContainerInit(t initType, pipe *os.File) (initer, error) { +func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd int) (initer, error) { var config *initConfig if err := json.NewDecoder(pipe).Decode(&config); err != nil { return nil, err @@ -75,13 +85,17 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) { switch t { case initSetns: return &linuxSetnsInit{ - config: config, + pipe: pipe, + consoleSocket: consoleSocket, + config: config, }, nil case initStandard: return &linuxStandardInit{ - pipe: pipe, - parentPid: syscall.Getppid(), - config: config, + pipe: pipe, + consoleSocket: consoleSocket, + parentPid: unix.Getppid(), + config: config, + fifoFd: fifoFd, }, nil } return nil, fmt.Errorf("unknown init type %q", t) @@ -110,62 +124,103 @@ func finalizeNamespace(config *initConfig) error { // inherited are marked close-on-exec so they stay out of the // container if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil { - return err + return errors.Wrap(err, "close exec fds") } - capabilities := config.Config.Capabilities + capabilities := &configs.Capabilities{} if config.Capabilities != nil { capabilities = config.Capabilities + } else if config.Config.Capabilities != nil { + capabilities = config.Config.Capabilities } - w, err := newCapWhitelist(capabilities) + w, err := newContainerCapList(capabilities) if err != nil { return err } // drop capabilities in bounding set before changing user - if err := w.dropBoundingSet(); err != nil { - return err + if err := w.ApplyBoundingSet(); err != nil { + return errors.Wrap(err, "apply bounding set") } // preserve existing capabilities while we change users if err := system.SetKeepCaps(); err != nil { - return err + return errors.Wrap(err, "set keep caps") } if err := setupUser(config); err != nil { - return err + return errors.Wrap(err, "setup user") } if err := system.ClearKeepCaps(); err != nil { - return err + return errors.Wrap(err, "clear keep caps") } - // drop all other capabilities - if err := w.drop(); err != nil { - return err + if err := w.ApplyCaps(); err != nil { + return errors.Wrap(err, "apply caps") } if config.Cwd != "" { - if err := syscall.Chdir(config.Cwd); err != nil { - return err + if err := unix.Chdir(config.Cwd); err != nil { + return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %v", config.Cwd, err) } } return nil } +// setupConsole sets up the console from inside the container, and sends the +// master pty fd to the config.Pipe (using cmsg). This is done to ensure that +// consoles are scoped to a container properly (see runc#814 and the many +// issues related to that). This has to be run *after* we've pivoted to the new +// rootfs (and the users' configuration is entirely set up). +func setupConsole(socket *os.File, config *initConfig, mount bool) error { + defer socket.Close() + // At this point, /dev/ptmx points to something that we would expect. We + // used to change the owner of the slave path, but since the /dev/pts mount + // can have gid=X set (at the users' option). So touching the owner of the + // slave PTY is not necessary, as the kernel will handle that for us. Note + // however, that setupUser (specifically fixStdioPermissions) *will* change + // the UID owner of the console to be the user the process will run as (so + // they can actually control their console). + + pty, slavePath, err := console.NewPty() + if err != nil { + return err + } + + if config.ConsoleHeight != 0 && config.ConsoleWidth != 0 { + err = pty.Resize(console.WinSize{ + Height: config.ConsoleHeight, + Width: config.ConsoleWidth, + }) + + if err != nil { + return err + } + } + + // After we return from here, we don't need the console anymore. + defer pty.Close() + + // Mount the console inside our rootfs. + if mount { + if err := mountConsole(slavePath); err != nil { + return err + } + } + // While we can access console.master, using the API is a good idea. + if err := utils.SendFd(socket, pty.Name(), pty.Fd()); err != nil { + return err + } + // Now, dup over all the things. + return dupStdio(slavePath) +} + // syncParentReady sends to the given pipe a JSON payload which indicates that // the init is ready to Exec the child process. It then waits for the parent to // indicate that it is cleared to Exec. func syncParentReady(pipe io.ReadWriter) error { // Tell parent. - if err := utils.WriteJSON(pipe, syncT{procReady}); err != nil { + if err := writeSync(pipe, procReady); err != nil { return err } + // Wait for parent to give the all-clear. - var procSync syncT - if err := json.NewDecoder(pipe).Decode(&procSync); err != nil { - if err == io.EOF { - return fmt.Errorf("parent closed synchronisation channel") - } - if procSync.Type != procRun { - return fmt.Errorf("invalid synchronisation flag from parent") - } - } - return nil + return readSync(pipe, procRun) } // syncParentHooks sends to the given pipe a JSON payload which indicates that @@ -173,66 +228,96 @@ func syncParentReady(pipe io.ReadWriter) error { // indicate that it is cleared to resume. func syncParentHooks(pipe io.ReadWriter) error { // Tell parent. - if err := utils.WriteJSON(pipe, syncT{procHooks}); err != nil { + if err := writeSync(pipe, procHooks); err != nil { return err } + // Wait for parent to give the all-clear. - var procSync syncT - if err := json.NewDecoder(pipe).Decode(&procSync); err != nil { - if err == io.EOF { - return fmt.Errorf("parent closed synchronisation channel") - } - if procSync.Type != procResume { - return fmt.Errorf("invalid synchronisation flag from parent") - } - } - return nil + return readSync(pipe, procResume) } // setupUser changes the groups, gid, and uid for the user inside the container func setupUser(config *initConfig) error { // Set up defaults. defaultExecUser := user.ExecUser{ - Uid: syscall.Getuid(), - Gid: syscall.Getgid(), + Uid: 0, + Gid: 0, Home: "/", } + passwdPath, err := user.GetPasswdPath() if err != nil { return err } + groupPath, err := user.GetGroupPath() if err != nil { return err } + execUser, err := user.GetExecUserPath(config.User, &defaultExecUser, passwdPath, groupPath) if err != nil { return err } var addGroups []int - if len(config.Config.AdditionalGroups) > 0 { - addGroups, err = user.GetAdditionalGroupsPath(config.Config.AdditionalGroups, groupPath) + if len(config.AdditionalGroups) > 0 { + addGroups, err = user.GetAdditionalGroupsPath(config.AdditionalGroups, groupPath) if err != nil { return err } } - // before we change to the container's user make sure that the processes STDIO - // is correctly owned by the user that we are switching to. - if err := fixStdioPermissions(execUser); err != nil { + + // Rather than just erroring out later in setuid(2) and setgid(2), check + // that the user is mapped here. + if _, err := config.Config.HostUID(execUser.Uid); err != nil { + return fmt.Errorf("cannot set uid to unmapped user in user namespace") + } + if _, err := config.Config.HostGID(execUser.Gid); err != nil { + return fmt.Errorf("cannot set gid to unmapped user in user namespace") + } + + if config.RootlessEUID { + // We cannot set any additional groups in a rootless container and thus + // we bail if the user asked us to do so. TODO: We currently can't do + // this check earlier, but if libcontainer.Process.User was typesafe + // this might work. + if len(addGroups) > 0 { + return fmt.Errorf("cannot set any additional groups in a rootless container") + } + } + + // Before we change to the container's user make sure that the processes + // STDIO is correctly owned by the user that we are switching to. + if err := fixStdioPermissions(config, execUser); err != nil { return err } - suppGroups := append(execUser.Sgids, addGroups...) - if err := syscall.Setgroups(suppGroups); err != nil { + + setgroups, err := ioutil.ReadFile("/proc/self/setgroups") + if err != nil && !os.IsNotExist(err) { return err } + // This isn't allowed in an unprivileged user namespace since Linux 3.19. + // There's nothing we can do about /etc/group entries, so we silently + // ignore setting groups here (since the user didn't explicitly ask us to + // set the group). + allowSupGroups := !config.RootlessEUID && strings.TrimSpace(string(setgroups)) != "deny" + + if allowSupGroups { + suppGroups := append(execUser.Sgids, addGroups...) + if err := unix.Setgroups(suppGroups); err != nil { + return err + } + } + if err := system.Setgid(execUser.Gid); err != nil { return err } if err := system.Setuid(execUser.Uid); err != nil { return err } + // if we didn't get HOME already, set it based on the user's HOME if envHome := os.Getenv("HOME"); envHome == "" { if err := os.Setenv("HOME", execUser.Home); err != nil { @@ -245,9 +330,9 @@ func setupUser(config *initConfig) error { // fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user. // The ownership needs to match because it is created outside of the container and needs to be // localized. -func fixStdioPermissions(u *user.ExecUser) error { - var null syscall.Stat_t - if err := syscall.Stat("/dev/null", &null); err != nil { +func fixStdioPermissions(config *initConfig, u *user.ExecUser) error { + var null unix.Stat_t + if err := unix.Stat("/dev/null", &null); err != nil { return err } for _, fd := range []uintptr{ @@ -255,15 +340,32 @@ func fixStdioPermissions(u *user.ExecUser) error { os.Stderr.Fd(), os.Stdout.Fd(), } { - var s syscall.Stat_t - if err := syscall.Fstat(int(fd), &s); err != nil { + var s unix.Stat_t + if err := unix.Fstat(int(fd), &s); err != nil { return err } - // skip chown of /dev/null if it was used as one of the STDIO fds. + + // Skip chown of /dev/null if it was used as one of the STDIO fds. if s.Rdev == null.Rdev { continue } - if err := syscall.Fchown(int(fd), u.Uid, u.Gid); err != nil { + + // We only change the uid owner (as it is possible for the mount to + // prefer a different gid, and there's no reason for us to change it). + // The reason why we don't just leave the default uid=X mount setup is + // that users expect to be able to actually use their console. Without + // this code, you couldn't effectively run as a non-root user inside a + // container and also have a console set up. + if err := unix.Fchown(int(fd), u.Uid, int(s.Gid)); err != nil { + // If we've hit an EINVAL then s.Gid isn't mapped in the user + // namespace. If we've hit an EPERM then the inode's current owner + // is not mapped in our user namespace (in particular, + // privileged_wrt_inode_uidgid() has failed). In either case, we + // are in a configuration where it's better for us to just not + // touch the stdio rather than bail at this point. + if err == unix.EINVAL || err == unix.EPERM { + continue + } return err } } @@ -316,26 +418,60 @@ func setupRoute(config *configs.Config) error { return nil } -func setupRlimits(limits []configs.Rlimit) error { +func setupRlimits(limits []configs.Rlimit, pid int) error { for _, rlimit := range limits { - l := &syscall.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft} - if err := syscall.Setrlimit(rlimit.Type, l); err != nil { + if err := system.Prlimit(pid, rlimit.Type, unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}); err != nil { return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err) } } return nil } -func setOomScoreAdj(oomScoreAdj int, pid int) error { - path := fmt.Sprintf("/proc/%d/oom_score_adj", pid) +const _P_PID = 1 + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_pid is the only field we use + si_pid int32 + // Pad to 128 bytes as detailed in blockUntilWaitable + pad [96]byte +} + +// isWaitable returns true if the process has exited false otherwise. +// Its based off blockUntilWaitable in src/os/wait_waitid.go +func isWaitable(pid int) (bool, error) { + si := &siginfo{} + _, _, e := unix.Syscall6(unix.SYS_WAITID, _P_PID, uintptr(pid), uintptr(unsafe.Pointer(si)), unix.WEXITED|unix.WNOWAIT|unix.WNOHANG, 0, 0) + if e != 0 { + return false, os.NewSyscallError("waitid", e) + } - return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0600) + return si.si_pid != 0, nil } -// killCgroupProcesses freezes then iterates over all the processes inside the -// manager's cgroups sending a SIGKILL to each process then waiting for them to -// exit. -func killCgroupProcesses(m cgroups.Manager) error { +// isNoChildren returns true if err represents a unix.ECHILD (formerly syscall.ECHILD) false otherwise +func isNoChildren(err error) bool { + switch err := err.(type) { + case syscall.Errno: + if err == unix.ECHILD { + return true + } + case *os.SyscallError: + if err.Err == unix.ECHILD { + return true + } + } + return false +} + +// signalAllProcesses freezes then iterates over all the processes inside the +// manager's cgroups sending the signal s to them. +// If s is SIGKILL then it will wait for each process to exit. +// For all other signals it will check if the process is ready to report its +// exit status and only if it is will a wait be performed. +func signalAllProcesses(m cgroups.Manager, s os.Signal) error { var procs []*os.Process if err := m.Freeze(configs.Frozen); err != nil { logrus.Warn(err) @@ -346,19 +482,54 @@ func killCgroupProcesses(m cgroups.Manager) error { return err } for _, pid := range pids { - if p, err := os.FindProcess(pid); err == nil { - procs = append(procs, p) - if err := p.Kill(); err != nil { - logrus.Warn(err) - } + p, err := os.FindProcess(pid) + if err != nil { + logrus.Warn(err) + continue + } + procs = append(procs, p) + if err := p.Signal(s); err != nil { + logrus.Warn(err) } } if err := m.Freeze(configs.Thawed); err != nil { logrus.Warn(err) } + + subreaper, err := system.GetSubreaper() + if err != nil { + // The error here means that PR_GET_CHILD_SUBREAPER is not + // supported because this code might run on a kernel older + // than 3.4. We don't want to throw an error in that case, + // and we simplify things, considering there is no subreaper + // set. + subreaper = 0 + } + for _, p := range procs { - if _, err := p.Wait(); err != nil { - logrus.Warn(err) + if s != unix.SIGKILL { + if ok, err := isWaitable(p.Pid); err != nil { + if !isNoChildren(err) { + logrus.Warn("signalAllProcesses: ", p.Pid, err) + } + continue + } else if !ok { + // Not ready to report so don't wait + continue + } + } + + // In case a subreaper has been setup, this code must not + // wait for the process. Otherwise, we cannot be sure the + // current process will be reaped by the subreaper, while + // the subreaper might be waiting for this process in order + // to retrieve its exit code. + if subreaper == 0 { + if _, err := p.Wait(); err != nil { + if !isNoChildren(err) { + logrus.Warn("wait: ", err) + } + } } } return nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go index a71c172a3c2ca388e82b94969704ad2490244d0e..63fa14f0f74ac15e19fa80a6d8d67c9e8f979cd6 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go @@ -5,13 +5,15 @@ import ( "bytes" "io/ioutil" "os" + "os/exec" "path/filepath" "strings" - "syscall" "testing" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/configs" + + "golang.org/x/sys/unix" ) func showFile(t *testing.T, fname string) error { @@ -38,7 +40,22 @@ func showFile(t *testing.T, fname string) error { return nil } +func TestUsernsCheckpoint(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + t.Skip("userns is unsupported") + } + cmd := exec.Command("criu", "check", "--feature", "userns") + if err := cmd.Run(); err != nil { + t.Skip("Unable to c/r a container with userns") + } + testCheckpoint(t, true) +} + func TestCheckpoint(t *testing.T) { + testCheckpoint(t, false) +} + +func testCheckpoint(t *testing.T, userns bool) { if testing.Short() { return } @@ -59,9 +76,15 @@ func TestCheckpoint(t *testing.T) { config.Mounts = append(config.Mounts, &configs.Mount{ Destination: "/sys/fs/cgroup", Device: "cgroup", - Flags: defaultMountFlags | syscall.MS_RDONLY, + Flags: defaultMountFlags | unix.MS_RDONLY, }) + if userns { + config.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) + } + factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { @@ -87,9 +110,10 @@ func TestCheckpoint(t *testing.T) { Env: standardEnvironment, Stdin: stdinR, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) stdinR.Close() defer stdinW.Close() if err != nil { @@ -106,6 +130,33 @@ func TestCheckpoint(t *testing.T) { t.Fatal(err) } + parentDir, err := ioutil.TempDir("", "criu-parent") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(parentDir) + + preDumpOpts := &libcontainer.CriuOpts{ + ImagesDirectory: parentDir, + WorkDirectory: parentDir, + PreDump: true, + } + preDumpLog := filepath.Join(preDumpOpts.WorkDirectory, "dump.log") + + if err := container.Checkpoint(preDumpOpts); err != nil { + showFile(t, preDumpLog) + t.Fatal(err) + } + + state, err := container.Status() + if err != nil { + t.Fatal(err) + } + + if state != libcontainer.Running { + t.Fatal("Unexpected preDump state: ", state) + } + imagesDir, err := ioutil.TempDir("", "criu") if err != nil { t.Fatal(err) @@ -115,6 +166,7 @@ func TestCheckpoint(t *testing.T) { checkpointOpts := &libcontainer.CriuOpts{ ImagesDirectory: imagesDir, WorkDirectory: imagesDir, + ParentImage: "../criu-parent", } dumpLog := filepath.Join(checkpointOpts.WorkDirectory, "dump.log") restoreLog := filepath.Join(checkpointOpts.WorkDirectory, "restore.log") @@ -124,12 +176,12 @@ func TestCheckpoint(t *testing.T) { t.Fatal(err) } - state, err := container.Status() + state, err = container.Status() if err != nil { t.Fatal(err) } - if state != libcontainer.Running { + if state != libcontainer.Stopped { t.Fatal("Unexpected state checkpoint: ", state) } @@ -154,6 +206,7 @@ func TestCheckpoint(t *testing.T) { Cwd: "/", Stdin: restoreStdinR, Stdout: &stdout, + Init: true, } err = container.Restore(restoreProcessConfig, checkpointOpts) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/exec_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/exec_test.go index 22a9afbfc251d61d58241db255f8b545cf618cd7..eb0f987fc8e8c139f67e06212430870eb139e195 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/exec_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/exec_test.go @@ -2,6 +2,7 @@ package integration import ( "bytes" + "encoding/json" "fmt" "io/ioutil" "os" @@ -10,12 +11,14 @@ import ( "reflect" "strconv" "strings" - "syscall" "testing" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" + + "golang.org/x/sys/unix" ) func TestExecPS(t *testing.T) { @@ -38,12 +41,12 @@ func testExecPS(t *testing.T, userns bool) { defer remove(rootfs) config := newTemplateConfig(rootfs) if userns { - config.UidMappings = []configs.IDMap{{0, 0, 1000}} - config.GidMappings = []configs.IDMap{{0, 0, 1000}} + config.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) } - buffers, exitCode, err := runContainer(config, "", "ps") + buffers, exitCode, err := runContainer(config, "", "ps", "-o", "pid,user,comm") if err != nil { t.Fatalf("%s: %s", buffers, err) } @@ -158,6 +161,18 @@ func TestIPCBadPath(t *testing.T) { } func TestRlimit(t *testing.T) { + testRlimit(t, false) +} + +func TestUsernsRlimit(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + t.Skip("userns is unsupported") + } + + testRlimit(t, true) +} + +func testRlimit(t *testing.T, userns bool) { if testing.Short() { return } @@ -167,6 +182,19 @@ func TestRlimit(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) + if userns { + config.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) + } + + // ensure limit is lower than what the config requests to test that in a user namespace + // the Setrlimit call happens early enough that we still have permissions to raise the limit. + ok(t, unix.Setrlimit(unix.RLIMIT_NOFILE, &unix.Rlimit{ + Max: 1024, + Cur: 1024, + })) + out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n") ok(t, err) if limit := strings.TrimSpace(out.Stdout.String()); limit != "1025" { @@ -174,17 +202,6 @@ func TestRlimit(t *testing.T) { } } -func newTestRoot() (string, error) { - dir, err := ioutil.TempDir("", "libcontainer") - if err != nil { - return "", err - } - if err := os.MkdirAll(dir, 0700); err != nil { - return "", err - } - return dir, nil -} - func TestEnter(t *testing.T) { if testing.Short() { return @@ -215,8 +232,9 @@ func TestEnter(t *testing.T) { Env: standardEnvironment, Stdin: stdinR, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -234,7 +252,7 @@ func TestEnter(t *testing.T) { pconfig2.Stdin = stdinR2 pconfig2.Stdout = &stdout2 - err = container.Start(&pconfig2) + err = container.Run(&pconfig2) stdinR2.Close() defer stdinW2.Close() ok(t, err) @@ -304,8 +322,9 @@ func TestProcessEnv(t *testing.T) { }, Stdin: nil, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -324,7 +343,7 @@ func TestProcessEnv(t *testing.T) { } } -func TestProcessCaps(t *testing.T) { +func TestProcessEmptyCaps(t *testing.T) { if testing.Short() { return } @@ -337,23 +356,78 @@ func TestProcessCaps(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) + config.Capabilities = nil container, err := factory.Create("test", config) ok(t, err) defer container.Destroy() - processCaps := append(config.Capabilities, "CAP_NET_ADMIN") + var stdout bytes.Buffer + pconfig := libcontainer.Process{ + Cwd: "/", + Args: []string{"sh", "-c", "cat /proc/self/status"}, + Env: standardEnvironment, + Stdin: nil, + Stdout: &stdout, + Init: true, + } + err = container.Run(&pconfig) + ok(t, err) + + // Wait for process + waitProcess(&pconfig, t) + + outputStatus := string(stdout.Bytes()) + + lines := strings.Split(outputStatus, "\n") + + effectiveCapsLine := "" + for _, l := range lines { + line := strings.TrimSpace(l) + if strings.Contains(line, "CapEff:") { + effectiveCapsLine = line + break + } + } + + if effectiveCapsLine == "" { + t.Fatal("Couldn't find effective caps: ", outputStatus) + } +} + +func TestProcessCaps(t *testing.T) { + if testing.Short() { + return + } + root, err := newTestRoot() + ok(t, err) + defer os.RemoveAll(root) + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + + container, err := factory.Create("test", config) + ok(t, err) + defer container.Destroy() var stdout bytes.Buffer pconfig := libcontainer.Process{ Cwd: "/", Args: []string{"sh", "-c", "cat /proc/self/status"}, Env: standardEnvironment, - Capabilities: processCaps, Stdin: nil, Stdout: &stdout, + Capabilities: &configs.Capabilities{}, + Init: true, } - err = container.Start(&pconfig) + pconfig.Capabilities.Bounding = append(config.Capabilities.Bounding, "CAP_NET_ADMIN") + pconfig.Capabilities.Permitted = append(config.Capabilities.Permitted, "CAP_NET_ADMIN") + pconfig.Capabilities.Effective = append(config.Capabilities.Effective, "CAP_NET_ADMIN") + pconfig.Capabilities.Inheritable = append(config.Capabilities.Inheritable, "CAP_NET_ADMIN") + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -406,7 +480,6 @@ func TestAdditionalGroups(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) - config.AdditionalGroups = []string{"plugdev", "audio"} factory, err := libcontainer.New(root, libcontainer.Cgroupfs) ok(t, err) @@ -417,13 +490,15 @@ func TestAdditionalGroups(t *testing.T) { var stdout bytes.Buffer pconfig := libcontainer.Process{ - Cwd: "/", - Args: []string{"sh", "-c", "id", "-Gn"}, - Env: standardEnvironment, - Stdin: nil, - Stdout: &stdout, + Cwd: "/", + Args: []string{"sh", "-c", "id", "-Gn"}, + Env: standardEnvironment, + Stdin: nil, + Stdout: &stdout, + AdditionalGroups: []string{"plugdev", "audio"}, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -482,8 +557,9 @@ func testFreeze(t *testing.T, systemd bool) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(pconfig) + err = container.Run(pconfig) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -588,9 +664,9 @@ func testPids(t *testing.T, systemd bool) { } // Enforce a restrictive limit. 64 * /bin/true + 1 * shell should cause this - // to fail reliabily. + // to fail reliability. config.Cgroups.Resources.PidsLimit = 64 - out, ret, err := runContainer(config, "", "/bin/sh", "-c", ` + out, _, err := runContainer(config, "", "/bin/sh", "-c", ` /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true | @@ -693,8 +769,9 @@ func TestContainerState(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(p) + err = container.Run(p) if err != nil { t.Fatal(err) } @@ -738,7 +815,13 @@ func TestPassExtraFiles(t *testing.T) { var stdout bytes.Buffer pipeout1, pipein1, err := os.Pipe() + if err != nil { + t.Fatal(err) + } pipeout2, pipein2, err := os.Pipe() + if err != nil { + t.Fatal(err) + } process := libcontainer.Process{ Cwd: "/", Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, @@ -746,8 +829,9 @@ func TestPassExtraFiles(t *testing.T) { ExtraFiles: []*os.File{pipein1, pipein2}, Stdin: nil, Stdout: &stdout, + Init: true, } - err = container.Start(&process) + err = container.Run(&process) if err != nil { t.Fatal(err) } @@ -806,7 +890,7 @@ func TestMountCmds(t *testing.T) { Source: tmpDir, Destination: "/tmp", Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC, + Flags: unix.MS_BIND | unix.MS_REC, PremountCmds: []configs.Command{ {Path: "touch", Args: []string{filepath.Join(tmpDir, "hello")}}, {Path: "touch", Args: []string{filepath.Join(tmpDir, "world")}}, @@ -827,8 +911,9 @@ func TestMountCmds(t *testing.T) { Cwd: "/", Args: []string{"sh", "-c", "env"}, Env: standardEnvironment, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) if err != nil { t.Fatal(err) } @@ -876,8 +961,9 @@ func TestSysctl(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -901,7 +987,7 @@ func TestMountCgroupRO(t *testing.T) { config.Mounts = append(config.Mounts, &configs.Mount{ Destination: "/sys/fs/cgroup", Device: "cgroup", - Flags: defaultMountFlags | syscall.MS_RDONLY, + Flags: defaultMountFlags | unix.MS_RDONLY, }) buffers, exitCode, err := runContainer(config, "", "mount") @@ -1000,7 +1086,7 @@ func TestOomScoreAdj(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) - config.OomScoreAdj = 200 + config.OomScoreAdj = ptrInt(200) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) ok(t, err) @@ -1016,8 +1102,9 @@ func TestOomScoreAdj(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -1025,8 +1112,8 @@ func TestOomScoreAdj(t *testing.T) { outputOomScoreAdj := strings.TrimSpace(string(stdout.Bytes())) // Check that the oom_score_adj matches the value that was set as part of config. - if outputOomScoreAdj != strconv.Itoa(config.OomScoreAdj) { - t.Fatalf("Expected oom_score_adj %d; got %q", config.OomScoreAdj, outputOomScoreAdj) + if outputOomScoreAdj != strconv.Itoa(*config.OomScoreAdj) { + t.Fatalf("Expected oom_score_adj %d; got %q", *config.OomScoreAdj, outputOomScoreAdj) } } @@ -1034,31 +1121,83 @@ func TestHook(t *testing.T) { if testing.Short() { return } - root, err := newTestRoot() + + bundle, err := newTestBundle() ok(t, err) - defer os.RemoveAll(root) + defer remove(bundle) rootfs, err := newRootfs() ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) + expectedBundle := bundle + config.Labels = append(config.Labels, fmt.Sprintf("bundle=%s", expectedBundle)) + + getRootfsFromBundle := func(bundle string) (string, error) { + f, err := os.Open(filepath.Join(bundle, "config.json")) + if err != nil { + return "", err + } + + var config configs.Config + if err = json.NewDecoder(f).Decode(&config); err != nil { + return "", err + } + return config.Rootfs, nil + } + config.Hooks = &configs.Hooks{ Prestart: []configs.Hook{ - configs.NewFunctionHook(func(s configs.HookState) error { - f, err := os.Create(filepath.Join(s.Root, "test")) + configs.NewFunctionHook(func(s *specs.State) error { + if s.Bundle != expectedBundle { + t.Fatalf("Expected prestart hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle) + } + + root, err := getRootfsFromBundle(s.Bundle) + if err != nil { + return err + } + f, err := os.Create(filepath.Join(root, "test")) if err != nil { return err } return f.Close() }), }, + Poststart: []configs.Hook{ + configs.NewFunctionHook(func(s *specs.State) error { + if s.Bundle != expectedBundle { + t.Fatalf("Expected poststart hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle) + } + + root, err := getRootfsFromBundle(s.Bundle) + if err != nil { + return err + } + return ioutil.WriteFile(filepath.Join(root, "test"), []byte("hello world"), 0755) + }), + }, Poststop: []configs.Hook{ - configs.NewFunctionHook(func(s configs.HookState) error { - return os.RemoveAll(filepath.Join(s.Root, "test")) + configs.NewFunctionHook(func(s *specs.State) error { + if s.Bundle != expectedBundle { + t.Fatalf("Expected poststop hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle) + } + + root, err := getRootfsFromBundle(s.Bundle) + if err != nil { + return err + } + return os.RemoveAll(filepath.Join(root, "test")) }), }, } + + // write config of json format into config.json under bundle + f, err := os.OpenFile(filepath.Join(bundle, "config.json"), os.O_CREATE|os.O_RDWR, 0644) + ok(t, err) + ok(t, json.NewEncoder(f).Encode(config)) + container, err := factory.Create("test", config) ok(t, err) @@ -1069,8 +1208,9 @@ func TestHook(t *testing.T) { Env: standardEnvironment, Stdin: nil, Stdout: &stdout, + Init: true, } - err = container.Start(&pconfig) + err = container.Run(&pconfig) ok(t, err) // Wait for process @@ -1084,8 +1224,18 @@ func TestHook(t *testing.T) { t.Fatalf("ls output doesn't have the expected file: %s", outputLs) } + // Check that the file is written by the poststart hook + testFilePath := filepath.Join(rootfs, "test") + contents, err := ioutil.ReadFile(testFilePath) + if err != nil { + t.Fatalf("cannot read file '%s': %s", testFilePath, err) + } + if string(contents) != "hello world" { + t.Fatalf("Expected test file to contain 'hello world'; got '%s'", string(contents)) + } + if err := container.Destroy(); err != nil { - t.Fatalf("container destory %s", err) + t.Fatalf("container destroy %s", err) } fi, err := os.Stat(filepath.Join(rootfs, "test")) if err == nil || !os.IsNotExist(err) { @@ -1114,10 +1264,7 @@ func TestSTDIOPermissions(t *testing.T) { } func unmountOp(path string) error { - if err := syscall.Unmount(path, syscall.MNT_DETACH); err != nil { - return err - } - return nil + return unix.Unmount(path, unix.MNT_DETACH) } // Launch container with rootfsPropagation in rslave mode. Also @@ -1139,7 +1286,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) - config.RootPropagation = syscall.MS_SLAVE | syscall.MS_REC + config.RootPropagation = unix.MS_SLAVE | unix.MS_REC // Bind mount a volume dir1host, err := ioutil.TempDir("", "mnt1host") @@ -1148,9 +1295,9 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { // Make this dir a "shared" mount point. This will make sure a // slave relationship can be established in container. - err = syscall.Mount(dir1host, dir1host, "bind", syscall.MS_BIND|syscall.MS_REC, "") + err = unix.Mount(dir1host, dir1host, "bind", unix.MS_BIND|unix.MS_REC, "") ok(t, err) - err = syscall.Mount("", dir1host, "", syscall.MS_SHARED|syscall.MS_REC, "") + err = unix.Mount("", dir1host, "", unix.MS_SHARED|unix.MS_REC, "") ok(t, err) defer unmountOp(dir1host) @@ -1158,7 +1305,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { Source: dir1host, Destination: dir1cont, Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC}) + Flags: unix.MS_BIND | unix.MS_REC}) // TODO: systemd specific processing f := factory @@ -1175,9 +1322,10 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(pconfig) + err = container.Run(pconfig) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -1188,7 +1336,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { ok(t, err) defer os.RemoveAll(dir2host) - err = syscall.Mount(dir2host, dir2host, "bind", syscall.MS_BIND, "") + err = unix.Mount(dir2host, dir2host, "bind", unix.MS_BIND, "") defer unmountOp(dir2host) ok(t, err) @@ -1206,7 +1354,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { Stdout: &stdout2, } - err = container.Start(pconfig2) + err = container.Run(pconfig2) stdinR2.Close() defer stdinW2.Close() ok(t, err) @@ -1256,7 +1404,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) { ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) - config.RootPropagation = syscall.MS_PRIVATE + config.RootPropagation = unix.MS_PRIVATE // Bind mount a volume dir1host, err := ioutil.TempDir("", "mnt1host") @@ -1265,9 +1413,9 @@ func TestRootfsPropagationSharedMount(t *testing.T) { // Make this dir a "shared" mount point. This will make sure a // shared relationship can be established in container. - err = syscall.Mount(dir1host, dir1host, "bind", syscall.MS_BIND|syscall.MS_REC, "") + err = unix.Mount(dir1host, dir1host, "bind", unix.MS_BIND|unix.MS_REC, "") ok(t, err) - err = syscall.Mount("", dir1host, "", syscall.MS_SHARED|syscall.MS_REC, "") + err = unix.Mount("", dir1host, "", unix.MS_SHARED|unix.MS_REC, "") ok(t, err) defer unmountOp(dir1host) @@ -1275,7 +1423,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) { Source: dir1host, Destination: dir1cont, Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC}) + Flags: unix.MS_BIND | unix.MS_REC}) // TODO: systemd specific processing f := factory @@ -1292,9 +1440,10 @@ func TestRootfsPropagationSharedMount(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(pconfig) + err = container.Run(pconfig) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -1314,19 +1463,22 @@ func TestRootfsPropagationSharedMount(t *testing.T) { stdinR2, stdinW2, err := os.Pipe() ok(t, err) - // Provide CAP_SYS_ADMIN - processCaps := append(config.Capabilities, "CAP_SYS_ADMIN") - pconfig2 := &libcontainer.Process{ Cwd: "/", Args: []string{"mount", "--bind", dir2cont, dir2cont}, Env: standardEnvironment, Stdin: stdinR2, Stdout: &stdout2, - Capabilities: processCaps, + Capabilities: &configs.Capabilities{}, } - err = container.Start(pconfig2) + // Provide CAP_SYS_ADMIN + pconfig2.Capabilities.Bounding = append(config.Capabilities.Bounding, "CAP_SYS_ADMIN") + pconfig2.Capabilities.Permitted = append(config.Capabilities.Permitted, "CAP_SYS_ADMIN") + pconfig2.Capabilities.Effective = append(config.Capabilities.Effective, "CAP_SYS_ADMIN") + pconfig2.Capabilities.Inheritable = append(config.Capabilities.Inheritable, "CAP_SYS_ADMIN") + + err = container.Run(pconfig2) stdinR2.Close() defer stdinW2.Close() ok(t, err) @@ -1397,8 +1549,9 @@ func TestInitJoinPID(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR1, + Init: true, } - err = container1.Start(init1) + err = container1.Run(init1) stdinR1.Close() defer stdinW1.Close() ok(t, err) @@ -1408,7 +1561,7 @@ func TestInitJoinPID(t *testing.T) { ok(t, err) pidns1 := state1.NamespacePaths[configs.NEWPID] - // Start a container inside the existing pidns but with different cgroups + // Run a container inside the existing pidns but with different cgroups config2 := newTemplateConfig(rootfs) config2.Namespaces.Add(configs.NEWPID, pidns1) config2.Cgroups.Path = "integration/test2" @@ -1423,8 +1576,9 @@ func TestInitJoinPID(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR2, + Init: true, } - err = container2.Start(init2) + err = container2.Run(init2) stdinR2.Close() defer stdinW2.Close() ok(t, err) @@ -1454,7 +1608,7 @@ func TestInitJoinPID(t *testing.T) { Env: standardEnvironment, Stdout: buffers.Stdout, } - err = container1.Start(ps) + err = container1.Run(ps) ok(t, err) waitProcess(ps, t) @@ -1488,8 +1642,8 @@ func TestInitJoinNetworkAndUser(t *testing.T) { // Execute a long-running container config1 := newTemplateConfig(rootfs) - config1.UidMappings = []configs.IDMap{{0, 0, 1000}} - config1.GidMappings = []configs.IDMap{{0, 0, 1000}} + config1.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config1.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} config1.Namespaces = append(config1.Namespaces, configs.Namespace{Type: configs.NEWUSER}) container1, err := newContainer(config1) ok(t, err) @@ -1502,8 +1656,9 @@ func TestInitJoinNetworkAndUser(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR1, + Init: true, } - err = container1.Start(init1) + err = container1.Run(init1) stdinR1.Close() defer stdinW1.Close() ok(t, err) @@ -1514,14 +1669,14 @@ func TestInitJoinNetworkAndUser(t *testing.T) { netns1 := state1.NamespacePaths[configs.NEWNET] userns1 := state1.NamespacePaths[configs.NEWUSER] - // Start a container inside the existing pidns but with different cgroups + // Run a container inside the existing pidns but with different cgroups rootfs2, err := newRootfs() ok(t, err) defer remove(rootfs2) config2 := newTemplateConfig(rootfs2) - config2.UidMappings = []configs.IDMap{{0, 0, 1000}} - config2.GidMappings = []configs.IDMap{{0, 0, 1000}} + config2.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config2.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} config2.Namespaces.Add(configs.NEWNET, netns1) config2.Namespaces.Add(configs.NEWUSER, userns1) config2.Cgroups.Path = "integration/test2" @@ -1536,8 +1691,9 @@ func TestInitJoinNetworkAndUser(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR2, + Init: true, } - err = container2.Start(init2) + err = container2.Run(init2) stdinR2.Close() defer stdinW2.Close() ok(t, err) @@ -1568,3 +1724,110 @@ func TestInitJoinNetworkAndUser(t *testing.T) { stdinW1.Close() waitProcess(init1, t) } + +func TestTmpfsCopyUp(t *testing.T) { + if testing.Short() { + return + } + root, err := newTestRoot() + ok(t, err) + defer os.RemoveAll(root) + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + + config.Mounts = append(config.Mounts, &configs.Mount{ + Source: "tmpfs", + Destination: "/etc", + Device: "tmpfs", + Extensions: configs.EXT_COPYUP, + }) + + factory, err := libcontainer.New(root, libcontainer.Cgroupfs) + ok(t, err) + + container, err := factory.Create("test", config) + ok(t, err) + defer container.Destroy() + + var stdout bytes.Buffer + pconfig := libcontainer.Process{ + Args: []string{"ls", "/etc/passwd"}, + Env: standardEnvironment, + Stdin: nil, + Stdout: &stdout, + Init: true, + } + err = container.Run(&pconfig) + ok(t, err) + + // Wait for process + waitProcess(&pconfig, t) + + outputLs := string(stdout.Bytes()) + + // Check that the ls output has /etc/passwd + if !strings.Contains(outputLs, "/etc/passwd") { + t.Fatalf("/etc/passwd not copied up as expected: %v", outputLs) + } +} + +func TestCGROUPPrivate(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + t.Skip("cgroupns is unsupported") + } + if testing.Short() { + return + } + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + + l, err := os.Readlink("/proc/1/ns/cgroup") + ok(t, err) + + config := newTemplateConfig(rootfs) + config.Namespaces.Add(configs.NEWCGROUP, "") + buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/cgroup") + ok(t, err) + + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) + } + + if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l { + t.Fatalf("cgroup link should be private to the container but equals host %q %q", actual, l) + } +} + +func TestCGROUPHost(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + t.Skip("cgroupns is unsupported") + } + if testing.Short() { + return + } + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + + l, err := os.Readlink("/proc/1/ns/cgroup") + ok(t, err) + + config := newTemplateConfig(rootfs) + buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/cgroup") + ok(t, err) + + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) + } + + if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l { + t.Fatalf("cgroup link not equal to host link %q %q", actual, l) + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/execin_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/execin_test.go index 98dd2ac088fe77b076866b00b659d6bc5d72735c..14f8a596406f1779ef5633d296cf5b7a0555ff1c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/execin_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/execin_test.go @@ -5,15 +5,17 @@ import ( "fmt" "io" "os" - "os/exec" "strconv" "strings" - "syscall" "testing" "time" + "github.com/containerd/console" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/utils" + + "golang.org/x/sys/unix" ) func TestExecIn(t *testing.T) { @@ -36,8 +38,9 @@ func TestExecIn(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -52,7 +55,7 @@ func TestExecIn(t *testing.T) { Stderr: buffers.Stderr, } - err = container.Start(ps) + err = container.Run(ps) ok(t, err) waitProcess(ps, t) stdinW.Close() @@ -62,16 +65,39 @@ func TestExecIn(t *testing.T) { if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { t.Fatalf("unexpected running process, output %q", out) } + if strings.Contains(out, "\r") { + t.Fatalf("unexpected carriage-return in output") + } +} + +func TestExecInUsernsRlimit(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + t.Skip("userns is unsupported") + } + + testExecInRlimit(t, true) } func TestExecInRlimit(t *testing.T) { + testExecInRlimit(t, false) +} + +func testExecInRlimit(t *testing.T, userns bool) { if testing.Short() { return } + rootfs, err := newRootfs() ok(t, err) defer remove(rootfs) + config := newTemplateConfig(rootfs) + if userns { + config.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) + } + container, err := newContainer(config) ok(t, err) defer container.Destroy() @@ -83,8 +109,9 @@ func TestExecInRlimit(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -97,8 +124,13 @@ func TestExecInRlimit(t *testing.T) { Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Rlimits: []configs.Rlimit{ + // increase process rlimit higher than container rlimit to test per-process limit + {Type: unix.RLIMIT_NOFILE, Hard: 1026, Soft: 1026}, + }, + Init: true, } - err = container.Start(ps) + err = container.Run(ps) ok(t, err) waitProcess(ps, t) @@ -106,8 +138,67 @@ func TestExecInRlimit(t *testing.T) { waitProcess(process, t) out := buffers.Stdout.String() - if limit := strings.TrimSpace(out); limit != "1025" { - t.Fatalf("expected rlimit to be 1025, got %s", limit) + if limit := strings.TrimSpace(out); limit != "1026" { + t.Fatalf("expected rlimit to be 1026, got %s", limit) + } +} + +func TestExecInAdditionalGroups(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + container, err := newContainer(config) + ok(t, err) + defer container.Destroy() + + // Execute a first process in the container + stdinR, stdinW, err := os.Pipe() + ok(t, err) + process := &libcontainer.Process{ + Cwd: "/", + Args: []string{"cat"}, + Env: standardEnvironment, + Stdin: stdinR, + Init: true, + } + err = container.Run(process) + stdinR.Close() + defer stdinW.Close() + ok(t, err) + + var stdout bytes.Buffer + pconfig := libcontainer.Process{ + Cwd: "/", + Args: []string{"sh", "-c", "id", "-Gn"}, + Env: standardEnvironment, + Stdin: nil, + Stdout: &stdout, + AdditionalGroups: []string{"plugdev", "audio"}, + } + err = container.Run(&pconfig) + ok(t, err) + + // Wait for process + waitProcess(&pconfig, t) + + stdinW.Close() + waitProcess(process, t) + + outputGroups := string(stdout.Bytes()) + + // Check that the groups output has the groups that we specified + if !strings.Contains(outputGroups, "audio") { + t.Fatalf("Listed groups do not contain the audio group as expected: %v", outputGroups) + } + + if !strings.Contains(outputGroups, "plugdev") { + t.Fatalf("Listed groups do not contain the plugdev group as expected: %v", outputGroups) } } @@ -131,8 +222,9 @@ func TestExecInError(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer func() { stdinW.Close() @@ -142,26 +234,24 @@ func TestExecInError(t *testing.T) { }() ok(t, err) - var out bytes.Buffer - unexistent := &libcontainer.Process{ - Cwd: "/", - Args: []string{"unexistent"}, - Env: standardEnvironment, - Stdout: &out, - Stderr: &out, - } - err = container.Start(unexistent) - if err != nil { - t.Fatal(err) - } - ws, err := unexistent.Wait() - if err != nil { - if _, ok := err.(*exec.ExitError); !ok { - t.Fatal(err) + for i := 0; i < 42; i++ { + var out bytes.Buffer + unexistent := &libcontainer.Process{ + Cwd: "/", + Args: []string{"unexistent"}, + Env: standardEnvironment, + Stderr: &out, + } + err = container.Run(unexistent) + if err == nil { + t.Fatal("Should be an error") + } + if !strings.Contains(err.Error(), "executable file not found") { + t.Fatalf("Should be error about not found executable, got %s", err) + } + if !bytes.Contains(out.Bytes(), []byte("executable file not found")) { + t.Fatalf("executable file not found error not delivered to stdio:\n%s", out.String()) } - } - if s := ws.Sys().(syscall.WaitStatus).ExitStatus(); s != 127 { - t.Fatalf("expected wait status of 127 but received %d", s) } } @@ -185,8 +275,9 @@ func TestExecInTTY(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -197,15 +288,51 @@ func TestExecInTTY(t *testing.T) { Args: []string{"ps"}, Env: standardEnvironment, } - console, err := ps.NewConsole(0) + parent, child, err := utils.NewSockPair("console") + if err != nil { + ok(t, err) + } + defer parent.Close() + defer child.Close() + ps.ConsoleSocket = child + type cdata struct { + c console.Console + err error + } + dc := make(chan *cdata, 1) + go func() { + f, err := utils.RecvFd(parent) + if err != nil { + dc <- &cdata{ + err: err, + } + return + } + c, err := console.ConsoleFromFile(f) + if err != nil { + dc <- &cdata{ + err: err, + } + return + } + console.ClearONLCR(c.Fd()) + dc <- &cdata{ + c: c, + } + }() + err = container.Run(ps) + ok(t, err) + data := <-dc + if data.err != nil { + ok(t, data.err) + } + console := data.c copy := make(chan struct{}) go func() { io.Copy(&stdout, console) close(copy) }() ok(t, err) - err = container.Start(ps) - ok(t, err) select { case <-time.After(5 * time.Second): t.Fatal("Waiting for copy timed out") @@ -217,9 +344,12 @@ func TestExecInTTY(t *testing.T) { waitProcess(process, t) out := stdout.String() - if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") { + if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { t.Fatalf("unexpected running process, output %q", out) } + if strings.Contains(out, "\r") { + t.Fatalf("unexpected carriage-return in output") + } } func TestExecInEnvironment(t *testing.T) { @@ -242,8 +372,9 @@ func TestExecInEnvironment(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -261,8 +392,9 @@ func TestExecInEnvironment(t *testing.T) { Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Init: true, } - err = container.Start(process2) + err = container.Run(process2) ok(t, err) waitProcess(process2, t) @@ -306,8 +438,9 @@ func TestExecinPassExtraFiles(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() if err != nil { @@ -316,7 +449,13 @@ func TestExecinPassExtraFiles(t *testing.T) { var stdout bytes.Buffer pipeout1, pipein1, err := os.Pipe() + if err != nil { + t.Fatal(err) + } pipeout2, pipein2, err := os.Pipe() + if err != nil { + t.Fatal(err) + } inprocess := &libcontainer.Process{ Cwd: "/", Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, @@ -325,7 +464,7 @@ func TestExecinPassExtraFiles(t *testing.T) { Stdin: nil, Stdout: &stdout, } - err = container.Start(inprocess) + err = container.Run(inprocess) if err != nil { t.Fatal(err) } @@ -367,7 +506,7 @@ func TestExecInOomScoreAdj(t *testing.T) { ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) - config.OomScoreAdj = 200 + config.OomScoreAdj = ptrInt(200) container, err := newContainer(config) ok(t, err) defer container.Destroy() @@ -379,8 +518,9 @@ func TestExecInOomScoreAdj(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -394,7 +534,7 @@ func TestExecInOomScoreAdj(t *testing.T) { Stdout: buffers.Stdout, Stderr: buffers.Stderr, } - err = container.Start(ps) + err = container.Run(ps) ok(t, err) waitProcess(ps, t) @@ -402,8 +542,8 @@ func TestExecInOomScoreAdj(t *testing.T) { waitProcess(process, t) out := buffers.Stdout.String() - if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) { - t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj) + if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(*config.OomScoreAdj) { + t.Fatalf("expected oomScoreAdj to be %d, got %s", *config.OomScoreAdj, oomScoreAdj) } } @@ -418,8 +558,8 @@ func TestExecInUserns(t *testing.T) { ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) - config.UidMappings = []configs.IDMap{{0, 0, 1000}} - config.GidMappings = []configs.IDMap{{0, 0, 1000}} + config.UidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} + config.GidMappings = []configs.IDMap{{HostID: 0, ContainerID: 0, Size: 1000}} config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER}) container, err := newContainer(config) ok(t, err) @@ -434,8 +574,9 @@ func TestExecInUserns(t *testing.T) { Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, + Init: true, } - err = container.Start(process) + err = container.Run(process) stdinR.Close() defer stdinW.Close() ok(t, err) @@ -455,7 +596,7 @@ func TestExecInUserns(t *testing.T) { Stdout: buffers.Stdout, Stderr: os.Stderr, } - err = container.Start(process2) + err = container.Run(process2) ok(t, err) waitProcess(process2, t) stdinW.Close() diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/init_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/init_test.go index a892d988d09f31c367c793cd8c9237916b83f04e..8b1e53d99b9ca58f1dbeaaf38a2193a45b6701a8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/init_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/init_test.go @@ -1,17 +1,15 @@ package integration import ( - "fmt" "os" - "os/exec" "runtime" - "strconv" "testing" - "github.com/sirupsen/logrus" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" _ "github.com/opencontainers/runc/libcontainer/nsenter" + + "github.com/sirupsen/logrus" ) // init runs the libcontainer initialization code because of the busybox style needs @@ -27,25 +25,8 @@ func init() { logrus.Fatalf("unable to initialize for container: %s", err) } if err := factory.StartInitialization(); err != nil { - // return proper unix error codes - if exerr, ok := err.(*exec.Error); ok { - switch exerr.Err { - case os.ErrPermission: - fmt.Fprintln(os.Stderr, err) - os.Exit(126) - case exec.ErrNotFound: - fmt.Fprintln(os.Stderr, err) - os.Exit(127) - default: - if os.IsNotExist(exerr.Err) { - fmt.Fprintf(os.Stderr, "exec: %s: %v\n", strconv.Quote(exerr.Name), os.ErrNotExist) - os.Exit(127) - } - } - } logrus.Fatal(err) } - panic("init: init failed to start contianer") } var ( @@ -56,19 +37,19 @@ var ( func TestMain(m *testing.M) { var ( err error - ret int = 0 + ret int ) logrus.SetOutput(os.Stderr) logrus.SetLevel(logrus.InfoLevel) - factory, err = libcontainer.New(".", libcontainer.Cgroupfs) + factory, err = libcontainer.New("/run/libctTests", libcontainer.Cgroupfs) if err != nil { logrus.Error(err) os.Exit(1) } if systemd.UseSystemd() { - systemdFactory, err = libcontainer.New(".", libcontainer.SystemdCgroups) + systemdFactory, err = libcontainer.New("/run/libctTests", libcontainer.SystemdCgroups) if err != nil { logrus.Error(err) os.Exit(1) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go index 820773e64fbaa5d6f8962ff3a5af8765a9b81406..77f1a8d465506c4c68471966c3bea6e3d0ff1ca3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go @@ -48,9 +48,10 @@ func TestSeccompDenyGetcwd(t *testing.T) { Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Init: true, } - err = container.Start(pwd) + err = container.Run(pwd) if err != nil { t.Fatal(err) } @@ -101,8 +102,8 @@ func TestSeccompPermitWriteConditional(t *testing.T) { Args: []*configs.Arg{ { Index: 0, - Value: 1, - Op: configs.GreaterThan, + Value: 2, + Op: configs.EqualTo, }, }, }, @@ -123,9 +124,10 @@ func TestSeccompPermitWriteConditional(t *testing.T) { Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Init: true, } - err = container.Start(dmesg) + err = container.Run(dmesg) if err != nil { t.Fatal(err) } @@ -162,8 +164,8 @@ func TestSeccompDenyWriteConditional(t *testing.T) { Args: []*configs.Arg{ { Index: 0, - Value: 1, - Op: configs.GreaterThan, + Value: 2, + Op: configs.EqualTo, }, }, }, @@ -184,9 +186,10 @@ func TestSeccompDenyWriteConditional(t *testing.T) { Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Init: true, } - err = container.Start(dmesg) + err = container.Run(dmesg) if err != nil { t.Fatal(err) } @@ -217,3 +220,203 @@ func TestSeccompDenyWriteConditional(t *testing.T) { t.Fatalf("Expected output %s but got %s\n", expected, actual) } } + +func TestSeccompPermitWriteMultipleConditions(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootfs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + config.Seccomp = &configs.Seccomp{ + DefaultAction: configs.Allow, + Syscalls: []*configs.Syscall{ + { + Name: "write", + Action: configs.Errno, + Args: []*configs.Arg{ + { + Index: 0, + Value: 2, + Op: configs.EqualTo, + }, + { + Index: 2, + Value: 0, + Op: configs.NotEqualTo, + }, + }, + }, + }, + } + + buffers, exitCode, err := runContainer(config, "", "ls", "/") + if err != nil { + t.Fatalf("%s: %s", buffers, err) + } + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d buffers %s", exitCode, buffers) + } + // We don't need to verify the actual thing printed + // Just that something was written to stdout + if len(buffers.Stdout.String()) == 0 { + t.Fatalf("Nothing was written to stdout, write call failed!\n") + } +} + +func TestSeccompDenyWriteMultipleConditions(t *testing.T) { + if testing.Short() { + return + } + + // Only test if library version is v2.2.1 or higher + // Conditional filtering will always error in v2.2.0 and lower + major, minor, micro := libseccomp.GetLibraryVersion() + if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) { + return + } + + rootfs, err := newRootfs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + config.Seccomp = &configs.Seccomp{ + DefaultAction: configs.Allow, + Syscalls: []*configs.Syscall{ + { + Name: "write", + Action: configs.Errno, + Args: []*configs.Arg{ + { + Index: 0, + Value: 2, + Op: configs.EqualTo, + }, + { + Index: 2, + Value: 0, + Op: configs.NotEqualTo, + }, + }, + }, + }, + } + + buffers, exitCode, err := runContainer(config, "", "ls", "/does_not_exist") + if err == nil { + t.Fatalf("Expecting error return, instead got 0") + } + if exitCode == 0 { + t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode) + } + + expected := "" + actual := strings.Trim(buffers.Stderr.String(), "\n") + if actual != expected { + t.Fatalf("Expected output %s but got %s\n", expected, actual) + } +} + +func TestSeccompMultipleConditionSameArgDeniesStdout(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootfs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + // Prevent writing to both stdout and stderr + config := newTemplateConfig(rootfs) + config.Seccomp = &configs.Seccomp{ + DefaultAction: configs.Allow, + Syscalls: []*configs.Syscall{ + { + Name: "write", + Action: configs.Errno, + Args: []*configs.Arg{ + { + Index: 0, + Value: 1, + Op: configs.EqualTo, + }, + { + Index: 0, + Value: 2, + Op: configs.EqualTo, + }, + }, + }, + }, + } + + buffers, exitCode, err := runContainer(config, "", "ls", "/") + if err != nil { + t.Fatalf("%s: %s", buffers, err) + } + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d buffers %s", exitCode, buffers) + } + // Verify that nothing was printed + if len(buffers.Stdout.String()) != 0 { + t.Fatalf("Something was written to stdout, write call succeeded!\n") + } +} + +func TestSeccompMultipleConditionSameArgDeniesStderr(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootfs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + // Prevent writing to both stdout and stderr + config := newTemplateConfig(rootfs) + config.Seccomp = &configs.Seccomp{ + DefaultAction: configs.Allow, + Syscalls: []*configs.Syscall{ + { + Name: "write", + Action: configs.Errno, + Args: []*configs.Arg{ + { + Index: 0, + Value: 1, + Op: configs.EqualTo, + }, + { + Index: 0, + Value: 2, + Op: configs.EqualTo, + }, + }, + }, + }, + } + + buffers, exitCode, err := runContainer(config, "", "ls", "/does_not_exist") + if err == nil { + t.Fatalf("Expecting error return, instead got 0") + } + if exitCode == 0 { + t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode) + } + // Verify nothing was printed + if len(buffers.Stderr.String()) != 0 { + t.Fatalf("Something was written to stderr, write call succeeded!\n") + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/template_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/template_test.go index f54a849acf6d2fd93107b759128cce37a30b0fb6..5f7cab53b67cf740f21ba4eff72ff6f2cdf8d1e8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/template_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/template_test.go @@ -1,9 +1,9 @@ package integration import ( - "syscall" - "github.com/opencontainers/runc/libcontainer/configs" + + "golang.org/x/sys/unix" ) var standardEnvironment = []string{ @@ -13,30 +13,97 @@ var standardEnvironment = []string{ "TERM=xterm", } -const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV +const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV // newTemplateConfig returns a base template for running a container // // it uses a network strategy of just setting a loopback interface // and the default setup for devices func newTemplateConfig(rootfs string) *configs.Config { + allowAllDevices := false return &configs.Config{ Rootfs: rootfs, - Capabilities: []string{ - "CAP_CHOWN", - "CAP_DAC_OVERRIDE", - "CAP_FSETID", - "CAP_FOWNER", - "CAP_MKNOD", - "CAP_NET_RAW", - "CAP_SETGID", - "CAP_SETUID", - "CAP_SETFCAP", - "CAP_SETPCAP", - "CAP_NET_BIND_SERVICE", - "CAP_SYS_CHROOT", - "CAP_KILL", - "CAP_AUDIT_WRITE", + Capabilities: &configs.Capabilities{ + Bounding: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Permitted: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Inheritable: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Ambient: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Effective: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, }, Namespaces: configs.Namespaces([]configs.Namespace{ {Type: configs.NEWNS}, @@ -49,12 +116,13 @@ func newTemplateConfig(rootfs string) *configs.Config { Path: "integration/test", Resources: &configs.Resources{ MemorySwappiness: nil, - AllowAllDevices: false, + AllowAllDevices: &allowAllDevices, AllowedDevices: configs.DefaultAllowedDevices, }, }, MaskPaths: []string{ "/proc/kcore", + "/sys/firmware", }, ReadonlyPaths: []string{ "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", @@ -72,14 +140,14 @@ func newTemplateConfig(rootfs string) *configs.Config { Source: "tmpfs", Destination: "/dev", Device: "tmpfs", - Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, + Flags: unix.MS_NOSUID | unix.MS_STRICTATIME, Data: "mode=755", }, { Source: "devpts", Destination: "/dev/pts", Device: "devpts", - Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, + Flags: unix.MS_NOSUID | unix.MS_NOEXEC, Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", }, { @@ -89,17 +157,20 @@ func newTemplateConfig(rootfs string) *configs.Config { Data: "mode=1777,size=65536k", Flags: defaultMountFlags, }, - { - Source: "mqueue", - Destination: "/dev/mqueue", - Device: "mqueue", - Flags: defaultMountFlags, - }, + /* + CI is broken on the debian based kernels with this + { + Source: "mqueue", + Destination: "/dev/mqueue", + Device: "mqueue", + Flags: defaultMountFlags, + }, + */ { Source: "sysfs", Destination: "/sys", Device: "sysfs", - Flags: defaultMountFlags | syscall.MS_RDONLY, + Flags: defaultMountFlags | unix.MS_RDONLY, }, }, Networks: []*configs.Network{ @@ -111,7 +182,7 @@ func newTemplateConfig(rootfs string) *configs.Config { }, Rlimits: []configs.Rlimit{ { - Type: syscall.RLIMIT_NOFILE, + Type: unix.RLIMIT_NOFILE, Hard: uint64(1025), Soft: uint64(1025), }, diff --git a/vendor/github.com/opencontainers/runc/libcontainer/integration/utils_test.go b/vendor/github.com/opencontainers/runc/libcontainer/integration/utils_test.go index e2ca10e00827699e9e5204bc62c4382a78dd1e67..541d42eb86be79825c323baa282d938ab6d706ad 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/integration/utils_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/integration/utils_test.go @@ -2,6 +2,8 @@ package integration import ( "bytes" + "crypto/md5" + "encoding/hex" "fmt" "io/ioutil" "os" @@ -11,11 +13,16 @@ import ( "strings" "syscall" "testing" + "time" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/configs" ) +func ptrInt(v int) *int { + return &v +} + func newStdBuffers() *stdBuffers { return &stdBuffers{ Stdin: bytes.NewBuffer(nil), @@ -62,6 +69,28 @@ func waitProcess(p *libcontainer.Process, t *testing.T) { } } +func newTestRoot() (string, error) { + dir, err := ioutil.TempDir("", "libcontainer") + if err != nil { + return "", err + } + if err := os.MkdirAll(dir, 0700); err != nil { + return "", err + } + return dir, nil +} + +func newTestBundle() (string, error) { + dir, err := ioutil.TempDir("", "bundle") + if err != nil { + return "", err + } + if err := os.MkdirAll(dir, 0700); err != nil { + return "", err + } + return dir, nil +} + // newRootfs creates a new tmp directory and copies the busybox root filesystem func newRootfs() (string, error) { dir, err := ioutil.TempDir("", "") @@ -84,7 +113,7 @@ func remove(dir string) { // copyBusybox copies the rootfs for a busybox container created for the test image // into the new directory for the specific test func copyBusybox(dest string) error { - out, err := exec.Command("sh", "-c", fmt.Sprintf("cp -R /busybox/* %s/", dest)).CombinedOutput() + out, err := exec.Command("sh", "-c", fmt.Sprintf("cp -a /busybox/* %s/", dest)).CombinedOutput() if err != nil { return fmt.Errorf("copy error %q: %q", err, out) } @@ -92,7 +121,9 @@ func copyBusybox(dest string) error { } func newContainer(config *configs.Config) (libcontainer.Container, error) { - return newContainerWithName("testCT", config) + h := md5.New() + h.Write([]byte(time.Now().String())) + return newContainerWithName(hex.EncodeToString(h.Sum(nil)), config) } func newContainerWithName(name string, config *configs.Config) (libcontainer.Container, error) { @@ -121,9 +152,10 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe Stdin: buffers.Stdin, Stdout: buffers.Stdout, Stderr: buffers.Stderr, + Init: true, } - err = container.Start(process) + err = container.Run(process) if err != nil { return buffers, -1, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go new file mode 100644 index 0000000000000000000000000000000000000000..9be62646628d4e80dcef7fcf5f470b92de185446 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go @@ -0,0 +1,773 @@ +// +build linux + +package intelrdt + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +/* + * About Intel RDT features: + * Intel platforms with new Xeon CPU support Resource Director Technology (RDT). + * Cache Allocation Technology (CAT) and Memory Bandwidth Allocation (MBA) are + * two sub-features of RDT. + * + * Cache Allocation Technology (CAT) provides a way for the software to restrict + * cache allocation to a defined 'subset' of L3 cache which may be overlapping + * with other 'subsets'. The different subsets are identified by class of + * service (CLOS) and each CLOS has a capacity bitmask (CBM). + * + * Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle + * over memory bandwidth for the software. A user controls the resource by + * indicating the percentage of maximum memory bandwidth or memory bandwidth + * limit in MBps unit if MBA Software Controller is enabled. + * + * More details about Intel RDT CAT and MBA can be found in the section 17.18 + * of Intel Software Developer Manual: + * https://software.intel.com/en-us/articles/intel-sdm + * + * About Intel RDT kernel interface: + * In Linux 4.10 kernel or newer, the interface is defined and exposed via + * "resource control" filesystem, which is a "cgroup-like" interface. + * + * Comparing with cgroups, it has similar process management lifecycle and + * interfaces in a container. But unlike cgroups' hierarchy, it has single level + * filesystem layout. + * + * CAT and MBA features are introduced in Linux 4.10 and 4.12 kernel via + * "resource control" filesystem. + * + * Intel RDT "resource control" filesystem hierarchy: + * mount -t resctrl resctrl /sys/fs/resctrl + * tree /sys/fs/resctrl + * /sys/fs/resctrl/ + * |-- info + * | |-- L3 + * | | |-- cbm_mask + * | | |-- min_cbm_bits + * | | |-- num_closids + * | |-- MB + * | |-- bandwidth_gran + * | |-- delay_linear + * | |-- min_bandwidth + * | |-- num_closids + * |-- ... + * |-- schemata + * |-- tasks + * |-- <container_id> + * |-- ... + * |-- schemata + * |-- tasks + * + * For runc, we can make use of `tasks` and `schemata` configuration for L3 + * cache and memory bandwidth resources constraints. + * + * The file `tasks` has a list of tasks that belongs to this group (e.g., + * <container_id>" group). Tasks can be added to a group by writing the task ID + * to the "tasks" file (which will automatically remove them from the previous + * group to which they belonged). New tasks created by fork(2) and clone(2) are + * added to the same group as their parent. + * + * The file `schemata` has a list of all the resources available to this group. + * Each resource (L3 cache, memory bandwidth) has its own line and format. + * + * L3 cache schema: + * It has allocation bitmasks/values for L3 cache on each socket, which + * contains L3 cache id and capacity bitmask (CBM). + * Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..." + * For example, on a two-socket machine, the schema line could be "L3:0=ff;1=c0" + * which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM is 0xc0. + * + * The valid L3 cache CBM is a *contiguous bits set* and number of bits that can + * be set is less than the max bit. The max bits in the CBM is varied among + * supported Intel CPU models. Kernel will check if it is valid when writing. + * e.g., default value 0xfffff in root indicates the max bits of CBM is 20 + * bits, which mapping to entire L3 cache capacity. Some valid CBM values to + * set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc. + * + * Memory bandwidth schema: + * It has allocation values for memory bandwidth on each socket, which contains + * L3 cache id and memory bandwidth. + * Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..." + * For example, on a two-socket machine, the schema line could be "MB:0=20;1=70" + * + * The minimum bandwidth percentage value for each CPU model is predefined and + * can be looked up through "info/MB/min_bandwidth". The bandwidth granularity + * that is allocated is also dependent on the CPU model and can be looked up at + * "info/MB/bandwidth_gran". The available bandwidth control steps are: + * min_bw + N * bw_gran. Intermediate values are rounded to the next control + * step available on the hardware. + * + * If MBA Software Controller is enabled through mount option "-o mba_MBps": + * mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl + * We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit + * instead of "percentages". The kernel underneath would use a software feedback + * mechanism or a "Software Controller" which reads the actual bandwidth using + * MBM counters and adjust the memory bandwidth percentages to ensure: + * "actual memory bandwidth < user specified memory bandwidth". + * + * For example, on a two-socket machine, the schema line could be + * "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0 + * and 7000 MBps memory bandwidth limit on socket 1. + * + * For more information about Intel RDT kernel interface: + * https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt + * + * An example for runc: + * Consider a two-socket machine with two L3 caches where the default CBM is + * 0x7ff and the max CBM length is 11 bits, and minimum memory bandwidth of 10% + * with a memory bandwidth granularity of 10%. + * + * Tasks inside the container only have access to the "upper" 7/11 of L3 cache + * on socket 0 and the "lower" 5/11 L3 cache on socket 1, and may use a + * maximum memory bandwidth of 20% on socket 0 and 70% on socket 1. + * + * "linux": { + * "intelRdt": { + * "l3CacheSchema": "L3:0=7f0;1=1f", + * "memBwSchema": "MB:0=20;1=70" + * } + * } + */ + +type Manager interface { + // Applies Intel RDT configuration to the process with the specified pid + Apply(pid int) error + + // Returns statistics for Intel RDT + GetStats() (*Stats, error) + + // Destroys the Intel RDT 'container_id' group + Destroy() error + + // Returns Intel RDT path to save in a state file and to be able to + // restore the object later + GetPath() string + + // Set Intel RDT "resource control" filesystem as configured. + Set(container *configs.Config) error +} + +// This implements interface Manager +type IntelRdtManager struct { + mu sync.Mutex + Config *configs.Config + Id string + Path string +} + +const ( + IntelRdtTasks = "tasks" +) + +var ( + // The absolute root path of the Intel RDT "resource control" filesystem + intelRdtRoot string + intelRdtRootLock sync.Mutex + + // The flag to indicate if Intel RDT/CAT is enabled + isCatEnabled bool + // The flag to indicate if Intel RDT/MBA is enabled + isMbaEnabled bool + // The flag to indicate if Intel RDT/MBA Software Controller is enabled + isMbaScEnabled bool +) + +type intelRdtData struct { + root string + config *configs.Config + pid int +} + +// Check if Intel RDT sub-features are enabled in init() +func init() { + // 1. Check if hardware and kernel support Intel RDT sub-features + // "cat_l3" flag for CAT and "mba" flag for MBA + isCatFlagSet, isMbaFlagSet, err := parseCpuInfoFile("/proc/cpuinfo") + if err != nil { + return + } + + // 2. Check if Intel RDT "resource control" filesystem is mounted + // The user guarantees to mount the filesystem + if !isIntelRdtMounted() { + return + } + + // 3. Double check if Intel RDT sub-features are available in + // "resource control" filesystem. Intel RDT sub-features can be + // selectively disabled or enabled by kernel command line + // (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel + if isCatFlagSet { + if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil { + isCatEnabled = true + } + } + if isMbaScEnabled { + // We confirm MBA Software Controller is enabled in step 2, + // MBA should be enabled because MBA Software Controller + // depends on MBA + isMbaEnabled = true + } else if isMbaFlagSet { + if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil { + isMbaEnabled = true + } + } +} + +// Return the mount point path of Intel RDT "resource control" filesysem +func findIntelRdtMountpointDir() (string, error) { + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return "", err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + text := s.Text() + fields := strings.Split(text, " ") + // Safe as mountinfo encodes mountpoints with spaces as \040. + index := strings.Index(text, " - ") + postSeparatorFields := strings.Fields(text[index+3:]) + numPostFields := len(postSeparatorFields) + + // This is an error as we can't detect if the mount is for "Intel RDT" + if numPostFields == 0 { + return "", fmt.Errorf("Found no fields post '-' in %q", text) + } + + if postSeparatorFields[0] == "resctrl" { + // Check that the mount is properly formatted. + if numPostFields < 3 { + return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) + } + + // Check if MBA Software Controller is enabled through mount option "-o mba_MBps" + if strings.Contains(postSeparatorFields[2], "mba_MBps") { + isMbaScEnabled = true + } + + return fields[4], nil + } + } + if err := s.Err(); err != nil { + return "", err + } + + return "", NewNotFoundError("Intel RDT") +} + +// Gets the root path of Intel RDT "resource control" filesystem +func getIntelRdtRoot() (string, error) { + intelRdtRootLock.Lock() + defer intelRdtRootLock.Unlock() + + if intelRdtRoot != "" { + return intelRdtRoot, nil + } + + root, err := findIntelRdtMountpointDir() + if err != nil { + return "", err + } + + if _, err := os.Stat(root); err != nil { + return "", err + } + + intelRdtRoot = root + return intelRdtRoot, nil +} + +func isIntelRdtMounted() bool { + _, err := getIntelRdtRoot() + if err != nil { + return false + } + + return true +} + +func parseCpuInfoFile(path string) (bool, bool, error) { + isCatFlagSet := false + isMbaFlagSet := false + + f, err := os.Open(path) + if err != nil { + return false, false, err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + if err := s.Err(); err != nil { + return false, false, err + } + + line := s.Text() + + // Search "cat_l3" and "mba" flags in first "flags" line + if strings.Contains(line, "flags") { + flags := strings.Split(line, " ") + // "cat_l3" flag for CAT and "mba" flag for MBA + for _, flag := range flags { + switch flag { + case "cat_l3": + isCatFlagSet = true + case "mba": + isMbaFlagSet = true + } + } + return isCatFlagSet, isMbaFlagSet, nil + } + } + return isCatFlagSet, isMbaFlagSet, nil +} + +func parseUint(s string, base, bitSize int) (uint64, error) { + value, err := strconv.ParseUint(s, base, bitSize) + if err != nil { + intValue, intErr := strconv.ParseInt(s, base, bitSize) + // 1. Handle negative values greater than MinInt64 (and) + // 2. Handle negative values lesser than MinInt64 + if intErr == nil && intValue < 0 { + return 0, nil + } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 { + return 0, nil + } + + return value, err + } + + return value, nil +} + +// Gets a single uint64 value from the specified file. +func getIntelRdtParamUint(path, file string) (uint64, error) { + fileName := filepath.Join(path, file) + contents, err := ioutil.ReadFile(fileName) + if err != nil { + return 0, err + } + + res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64) + if err != nil { + return res, fmt.Errorf("unable to parse %q as a uint from file %q", string(contents), fileName) + } + return res, nil +} + +// Gets a string value from the specified file +func getIntelRdtParamString(path, file string) (string, error) { + contents, err := ioutil.ReadFile(filepath.Join(path, file)) + if err != nil { + return "", err + } + + return strings.TrimSpace(string(contents)), nil +} + +func writeFile(dir, file, data string) error { + if dir == "" { + return fmt.Errorf("no such directory for %s", file) + } + if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0700); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", data, file, err) + } + return nil +} + +func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return nil, err + } + return &intelRdtData{ + root: rootPath, + config: c, + pid: pid, + }, nil +} + +// Get the read-only L3 cache information +func getL3CacheInfo() (*L3CacheInfo, error) { + l3CacheInfo := &L3CacheInfo{} + + rootPath, err := getIntelRdtRoot() + if err != nil { + return l3CacheInfo, err + } + + path := filepath.Join(rootPath, "info", "L3") + cbmMask, err := getIntelRdtParamString(path, "cbm_mask") + if err != nil { + return l3CacheInfo, err + } + minCbmBits, err := getIntelRdtParamUint(path, "min_cbm_bits") + if err != nil { + return l3CacheInfo, err + } + numClosids, err := getIntelRdtParamUint(path, "num_closids") + if err != nil { + return l3CacheInfo, err + } + + l3CacheInfo.CbmMask = cbmMask + l3CacheInfo.MinCbmBits = minCbmBits + l3CacheInfo.NumClosids = numClosids + + return l3CacheInfo, nil +} + +// Get the read-only memory bandwidth information +func getMemBwInfo() (*MemBwInfo, error) { + memBwInfo := &MemBwInfo{} + + rootPath, err := getIntelRdtRoot() + if err != nil { + return memBwInfo, err + } + + path := filepath.Join(rootPath, "info", "MB") + bandwidthGran, err := getIntelRdtParamUint(path, "bandwidth_gran") + if err != nil { + return memBwInfo, err + } + delayLinear, err := getIntelRdtParamUint(path, "delay_linear") + if err != nil { + return memBwInfo, err + } + minBandwidth, err := getIntelRdtParamUint(path, "min_bandwidth") + if err != nil { + return memBwInfo, err + } + numClosids, err := getIntelRdtParamUint(path, "num_closids") + if err != nil { + return memBwInfo, err + } + + memBwInfo.BandwidthGran = bandwidthGran + memBwInfo.DelayLinear = delayLinear + memBwInfo.MinBandwidth = minBandwidth + memBwInfo.NumClosids = numClosids + + return memBwInfo, nil +} + +// Get diagnostics for last filesystem operation error from file info/last_cmd_status +func getLastCmdStatus() (string, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return "", err + } + + path := filepath.Join(rootPath, "info") + lastCmdStatus, err := getIntelRdtParamString(path, "last_cmd_status") + if err != nil { + return "", err + } + + return lastCmdStatus, nil +} + +// WriteIntelRdtTasks writes the specified pid into the "tasks" file +func WriteIntelRdtTasks(dir string, pid int) error { + if dir == "" { + return fmt.Errorf("no such directory for %s", IntelRdtTasks) + } + + // Don't attach any pid if -1 is specified as a pid + if pid != -1 { + if err := ioutil.WriteFile(filepath.Join(dir, IntelRdtTasks), []byte(strconv.Itoa(pid)), 0700); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", pid, IntelRdtTasks, err) + } + } + return nil +} + +// Check if Intel RDT/CAT is enabled +func IsCatEnabled() bool { + return isCatEnabled +} + +// Check if Intel RDT/MBA is enabled +func IsMbaEnabled() bool { + return isMbaEnabled +} + +// Check if Intel RDT/MBA Software Controller is enabled +func IsMbaScEnabled() bool { + return isMbaScEnabled +} + +// Get the 'container_id' path in Intel RDT "resource control" filesystem +func GetIntelRdtPath(id string) (string, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return "", err + } + + path := filepath.Join(rootPath, id) + return path, nil +} + +// Applies Intel RDT configuration to the process with the specified pid +func (m *IntelRdtManager) Apply(pid int) (err error) { + // If intelRdt is not specified in config, we do nothing + if m.Config.IntelRdt == nil { + return nil + } + d, err := getIntelRdtData(m.Config, pid) + if err != nil && !IsNotFound(err) { + return err + } + + m.mu.Lock() + defer m.mu.Unlock() + path, err := d.join(m.Id) + if err != nil { + return err + } + + m.Path = path + return nil +} + +// Destroys the Intel RDT 'container_id' group +func (m *IntelRdtManager) Destroy() error { + m.mu.Lock() + defer m.mu.Unlock() + if err := os.RemoveAll(m.Path); err != nil { + return err + } + m.Path = "" + return nil +} + +// Returns Intel RDT path to save in a state file and to be able to +// restore the object later +func (m *IntelRdtManager) GetPath() string { + if m.Path == "" { + m.Path, _ = GetIntelRdtPath(m.Id) + } + return m.Path +} + +// Returns statistics for Intel RDT +func (m *IntelRdtManager) GetStats() (*Stats, error) { + // If intelRdt is not specified in config + if m.Config.IntelRdt == nil { + return nil, nil + } + + m.mu.Lock() + defer m.mu.Unlock() + stats := NewStats() + + rootPath, err := getIntelRdtRoot() + if err != nil { + return nil, err + } + // The read-only L3 cache and memory bandwidth schemata in root + tmpRootStrings, err := getIntelRdtParamString(rootPath, "schemata") + if err != nil { + return nil, err + } + schemaRootStrings := strings.Split(tmpRootStrings, "\n") + + // The L3 cache and memory bandwidth schemata in 'container_id' group + tmpStrings, err := getIntelRdtParamString(m.GetPath(), "schemata") + if err != nil { + return nil, err + } + schemaStrings := strings.Split(tmpStrings, "\n") + + if IsCatEnabled() { + // The read-only L3 cache information + l3CacheInfo, err := getL3CacheInfo() + if err != nil { + return nil, err + } + stats.L3CacheInfo = l3CacheInfo + + // The read-only L3 cache schema in root + for _, schemaRoot := range schemaRootStrings { + if strings.Contains(schemaRoot, "L3") { + stats.L3CacheSchemaRoot = strings.TrimSpace(schemaRoot) + } + } + + // The L3 cache schema in 'container_id' group + for _, schema := range schemaStrings { + if strings.Contains(schema, "L3") { + stats.L3CacheSchema = strings.TrimSpace(schema) + } + } + } + + if IsMbaEnabled() { + // The read-only memory bandwidth information + memBwInfo, err := getMemBwInfo() + if err != nil { + return nil, err + } + stats.MemBwInfo = memBwInfo + + // The read-only memory bandwidth information + for _, schemaRoot := range schemaRootStrings { + if strings.Contains(schemaRoot, "MB") { + stats.MemBwSchemaRoot = strings.TrimSpace(schemaRoot) + } + } + + // The memory bandwidth schema in 'container_id' group + for _, schema := range schemaStrings { + if strings.Contains(schema, "MB") { + stats.MemBwSchema = strings.TrimSpace(schema) + } + } + } + + return stats, nil +} + +// Set Intel RDT "resource control" filesystem as configured. +func (m *IntelRdtManager) Set(container *configs.Config) error { + // About L3 cache schema: + // It has allocation bitmasks/values for L3 cache on each socket, + // which contains L3 cache id and capacity bitmask (CBM). + // Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..." + // For example, on a two-socket machine, the schema line could be: + // L3:0=ff;1=c0 + // which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM + // is 0xc0. + // + // The valid L3 cache CBM is a *contiguous bits set* and number of + // bits that can be set is less than the max bit. The max bits in the + // CBM is varied among supported Intel CPU models. Kernel will check + // if it is valid when writing. e.g., default value 0xfffff in root + // indicates the max bits of CBM is 20 bits, which mapping to entire + // L3 cache capacity. Some valid CBM values to set in a group: + // 0xf, 0xf0, 0x3ff, 0x1f00 and etc. + // + // + // About memory bandwidth schema: + // It has allocation values for memory bandwidth on each socket, which + // contains L3 cache id and memory bandwidth. + // Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..." + // For example, on a two-socket machine, the schema line could be: + // "MB:0=20;1=70" + // + // The minimum bandwidth percentage value for each CPU model is + // predefined and can be looked up through "info/MB/min_bandwidth". + // The bandwidth granularity that is allocated is also dependent on + // the CPU model and can be looked up at "info/MB/bandwidth_gran". + // The available bandwidth control steps are: min_bw + N * bw_gran. + // Intermediate values are rounded to the next control step available + // on the hardware. + // + // If MBA Software Controller is enabled through mount option + // "-o mba_MBps": mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl + // We could specify memory bandwidth in "MBps" (Mega Bytes per second) + // unit instead of "percentages". The kernel underneath would use a + // software feedback mechanism or a "Software Controller" which reads + // the actual bandwidth using MBM counters and adjust the memory + // bandwidth percentages to ensure: + // "actual memory bandwidth < user specified memory bandwidth". + // + // For example, on a two-socket machine, the schema line could be + // "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on + // socket 0 and 7000 MBps memory bandwidth limit on socket 1. + if container.IntelRdt != nil { + path := m.GetPath() + l3CacheSchema := container.IntelRdt.L3CacheSchema + memBwSchema := container.IntelRdt.MemBwSchema + + // Write a single joint schema string to schemata file + if l3CacheSchema != "" && memBwSchema != "" { + if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil { + return NewLastCmdError(err) + } + } + + // Write only L3 cache schema string to schemata file + if l3CacheSchema != "" && memBwSchema == "" { + if err := writeFile(path, "schemata", l3CacheSchema); err != nil { + return NewLastCmdError(err) + } + } + + // Write only memory bandwidth schema string to schemata file + if l3CacheSchema == "" && memBwSchema != "" { + if err := writeFile(path, "schemata", memBwSchema); err != nil { + return NewLastCmdError(err) + } + } + } + + return nil +} + +func (raw *intelRdtData) join(id string) (string, error) { + path := filepath.Join(raw.root, id) + if err := os.MkdirAll(path, 0755); err != nil { + return "", NewLastCmdError(err) + } + + if err := WriteIntelRdtTasks(path, raw.pid); err != nil { + return "", NewLastCmdError(err) + } + return path, nil +} + +type NotFoundError struct { + ResourceControl string +} + +func (e *NotFoundError) Error() string { + return fmt.Sprintf("mountpoint for %s not found", e.ResourceControl) +} + +func NewNotFoundError(res string) error { + return &NotFoundError{ + ResourceControl: res, + } +} + +func IsNotFound(err error) bool { + if err == nil { + return false + } + _, ok := err.(*NotFoundError) + return ok +} + +type LastCmdError struct { + LastCmdStatus string + Err error +} + +func (e *LastCmdError) Error() string { + return fmt.Sprintf(e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus) +} + +func NewLastCmdError(err error) error { + lastCmdStatus, err1 := getLastCmdStatus() + if err1 == nil { + return &LastCmdError{ + LastCmdStatus: lastCmdStatus, + Err: err, + } + } + return err +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt_test.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt_test.go new file mode 100644 index 0000000000000000000000000000000000000000..a19b961b019e811c47a33e2a6b4716a740870f07 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt_test.go @@ -0,0 +1,122 @@ +// +build linux + +package intelrdt + +import ( + "strings" + "testing" +) + +func TestIntelRdtSetL3CacheSchema(t *testing.T) { + if !IsCatEnabled() { + return + } + + helper := NewIntelRdtTestUtil(t) + defer helper.cleanup() + + const ( + l3CacheSchemaBefore = "L3:0=f;1=f0" + l3CacheSchemeAfter = "L3:0=f0;1=f" + ) + + helper.writeFileContents(map[string]string{ + "schemata": l3CacheSchemaBefore + "\n", + }) + + helper.IntelRdtData.config.IntelRdt.L3CacheSchema = l3CacheSchemeAfter + intelrdt := &IntelRdtManager{ + Config: helper.IntelRdtData.config, + Path: helper.IntelRdtPath, + } + if err := intelrdt.Set(helper.IntelRdtData.config); err != nil { + t.Fatal(err) + } + + tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata") + if err != nil { + t.Fatalf("Failed to parse file 'schemata' - %s", err) + } + values := strings.Split(tmpStrings, "\n") + value := values[0] + + if value != l3CacheSchemeAfter { + t.Fatal("Got the wrong value, set 'schemata' failed.") + } +} + +func TestIntelRdtSetMemBwSchema(t *testing.T) { + if !IsMbaEnabled() { + return + } + + helper := NewIntelRdtTestUtil(t) + defer helper.cleanup() + + const ( + memBwSchemaBefore = "MB:0=20;1=70" + memBwSchemeAfter = "MB:0=70;1=20" + ) + + helper.writeFileContents(map[string]string{ + "schemata": memBwSchemaBefore + "\n", + }) + + helper.IntelRdtData.config.IntelRdt.MemBwSchema = memBwSchemeAfter + intelrdt := &IntelRdtManager{ + Config: helper.IntelRdtData.config, + Path: helper.IntelRdtPath, + } + if err := intelrdt.Set(helper.IntelRdtData.config); err != nil { + t.Fatal(err) + } + + tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata") + if err != nil { + t.Fatalf("Failed to parse file 'schemata' - %s", err) + } + values := strings.Split(tmpStrings, "\n") + value := values[0] + + if value != memBwSchemeAfter { + t.Fatal("Got the wrong value, set 'schemata' failed.") + } +} + +func TestIntelRdtSetMemBwScSchema(t *testing.T) { + if !IsMbaScEnabled() { + return + } + + helper := NewIntelRdtTestUtil(t) + defer helper.cleanup() + + const ( + memBwScSchemaBefore = "MB:0=5000;1=7000" + memBwScSchemeAfter = "MB:0=9000;1=4000" + ) + + helper.writeFileContents(map[string]string{ + "schemata": memBwScSchemaBefore + "\n", + }) + + helper.IntelRdtData.config.IntelRdt.MemBwSchema = memBwScSchemeAfter + intelrdt := &IntelRdtManager{ + Config: helper.IntelRdtData.config, + Path: helper.IntelRdtPath, + } + if err := intelrdt.Set(helper.IntelRdtData.config); err != nil { + t.Fatal(err) + } + + tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata") + if err != nil { + t.Fatalf("Failed to parse file 'schemata' - %s", err) + } + values := strings.Split(tmpStrings, "\n") + value := values[0] + + if value != memBwScSchemeAfter { + t.Fatal("Got the wrong value, set 'schemata' failed.") + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go new file mode 100644 index 0000000000000000000000000000000000000000..df5686f3b808c2a74b6faf9b7596c0bec2a5bf94 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go @@ -0,0 +1,40 @@ +// +build linux + +package intelrdt + +type L3CacheInfo struct { + CbmMask string `json:"cbm_mask,omitempty"` + MinCbmBits uint64 `json:"min_cbm_bits,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type MemBwInfo struct { + BandwidthGran uint64 `json:"bandwidth_gran,omitempty"` + DelayLinear uint64 `json:"delay_linear,omitempty"` + MinBandwidth uint64 `json:"min_bandwidth,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type Stats struct { + // The read-only L3 cache information + L3CacheInfo *L3CacheInfo `json:"l3_cache_info,omitempty"` + + // The read-only L3 cache schema in root + L3CacheSchemaRoot string `json:"l3_cache_schema_root,omitempty"` + + // The L3 cache schema in 'container_id' group + L3CacheSchema string `json:"l3_cache_schema,omitempty"` + + // The read-only memory bandwidth information + MemBwInfo *MemBwInfo `json:"mem_bw_info,omitempty"` + + // The read-only memory bandwidth schema in root + MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"` + + // The memory bandwidth schema in 'container_id' group + MemBwSchema string `json:"mem_bw_schema,omitempty"` +} + +func NewStats() *Stats { + return &Stats{} +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/util_test.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/util_test.go new file mode 100644 index 0000000000000000000000000000000000000000..970b6ce360e52896b80142ac0bb9aa36745ec6e2 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/util_test.go @@ -0,0 +1,67 @@ +// +build linux + +/* + * Utility for testing Intel RDT operations. + * Creates a mock of the Intel RDT "resource control" filesystem for the duration of the test. + */ +package intelrdt + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +type intelRdtTestUtil struct { + // intelRdt data to use in tests + IntelRdtData *intelRdtData + + // Path to the mock Intel RDT "resource control" filesystem directory + IntelRdtPath string + + // Temporary directory to store mock Intel RDT "resource control" filesystem + tempDir string + t *testing.T +} + +// Creates a new test util +func NewIntelRdtTestUtil(t *testing.T) *intelRdtTestUtil { + d := &intelRdtData{ + config: &configs.Config{ + IntelRdt: &configs.IntelRdt{}, + }, + } + tempDir, err := ioutil.TempDir("", "intelrdt_test") + if err != nil { + t.Fatal(err) + } + d.root = tempDir + testIntelRdtPath := filepath.Join(d.root, "resctrl") + if err != nil { + t.Fatal(err) + } + + // Ensure the full mock Intel RDT "resource control" filesystem path exists + err = os.MkdirAll(testIntelRdtPath, 0755) + if err != nil { + t.Fatal(err) + } + return &intelRdtTestUtil{IntelRdtData: d, IntelRdtPath: testIntelRdtPath, tempDir: tempDir, t: t} +} + +func (c *intelRdtTestUtil) cleanup() { + os.RemoveAll(c.tempDir) +} + +// Write the specified contents on the mock of the specified Intel RDT "resource control" files +func (c *intelRdtTestUtil) writeFileContents(fileContents map[string]string) { + for file, contents := range fileContents { + err := writeFile(c.IntelRdtPath, file, contents) + if err != nil { + c.t.Fatal(err) + } + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go index c37ca2133037c24d76ca2c16886cc4d62c19eef5..74dedd56ca8928d3ea777ae071b7bac013381303 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go @@ -1,51 +1,37 @@ // +build linux -package keyctl +package keys import ( "fmt" - "syscall" - "strings" "strconv" - "unsafe" -) + "strings" + + "github.com/pkg/errors" -const KEYCTL_JOIN_SESSION_KEYRING = 1 -const KEYCTL_SETPERM = 5 -const KEYCTL_DESCRIBE = 6 + "golang.org/x/sys/unix" +) type KeySerial uint32 func JoinSessionKeyring(name string) (KeySerial, error) { - var _name *byte = nil - var err error - - if len(name) > 0 { - _name, err = syscall.BytePtrFromString(name) - if err != nil { - return KeySerial(0), err - } - } - - sessKeyId, _, errn := syscall.Syscall(syscall.SYS_KEYCTL, KEYCTL_JOIN_SESSION_KEYRING, uintptr(unsafe.Pointer(_name)), 0) - if errn != 0 { - return 0, fmt.Errorf("could not create session key: %v", errn) + sessKeyId, err := unix.KeyctlJoinSessionKeyring(name) + if err != nil { + return 0, errors.Wrap(err, "create session key") } return KeySerial(sessKeyId), nil } -// modify permissions on a keyring by reading the current permissions, +// ModKeyringPerm modifies permissions on a keyring by reading the current permissions, // anding the bits with the given mask (clearing permissions) and setting // additional permission bits func ModKeyringPerm(ringId KeySerial, mask, setbits uint32) error { - dest := make([]byte, 1024) - destBytes := unsafe.Pointer(&dest[0]) - - if _, _, err := syscall.Syscall6(syscall.SYS_KEYCTL, uintptr(KEYCTL_DESCRIBE), uintptr(ringId), uintptr(destBytes), uintptr(len(dest)), 0, 0); err != 0 { + dest, err := unix.KeyctlString(unix.KEYCTL_DESCRIBE, int(ringId)) + if err != nil { return err } - res := strings.Split(string(dest), ";") + res := strings.Split(dest, ";") if len(res) < 5 { return fmt.Errorf("Destination buffer for key description is too small") } @@ -58,10 +44,5 @@ func ModKeyringPerm(ringId KeySerial, mask, setbits uint32) error { perm := (uint32(perm64) & mask) | setbits - if _, _, err := syscall.Syscall(syscall.SYS_KEYCTL, uintptr(KEYCTL_SETPERM), uintptr(ringId), uintptr(perm)); err != 0 { - return err - } - - return nil + return unix.KeyctlSetperm(int(ringId), perm) } - diff --git a/vendor/github.com/opencontainers/runc/libcontainer/label/label.go b/vendor/github.com/opencontainers/runc/libcontainer/label/label.go deleted file mode 100644 index 97dc6baef4cac761856161568481b07f48768e97..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/label/label.go +++ /dev/null @@ -1,76 +0,0 @@ -// +build !selinux !linux - -package label - -// InitLabels returns the process label and file labels to be used within -// the container. A list of options can be passed into this function to alter -// the labels. -func InitLabels(options []string) (string, string, error) { - return "", "", nil -} - -func GenLabels(options string) (string, string, error) { - return "", "", nil -} - -func FormatMountLabel(src string, mountLabel string) string { - return src -} - -func SetProcessLabel(processLabel string) error { - return nil -} - -func SetFileLabel(path string, fileLabel string) error { - return nil -} - -func SetFileCreateLabel(fileLabel string) error { - return nil -} - -func Relabel(path string, fileLabel string, shared bool) error { - return nil -} - -func GetPidLabel(pid int) (string, error) { - return "", nil -} - -func Init() { -} - -func ReserveLabel(label string) error { - return nil -} - -func UnreserveLabel(label string) error { - return nil -} - -// DupSecOpt takes an process label and returns security options that -// can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { - return nil -} - -// DisableSecOpt returns a security opt that can disable labeling -// support for future container processes -func DisableSecOpt() []string { - return nil -} - -// Validate checks that the label does not include unexpected options -func Validate(label string) error { - return nil -} - -// RelabelNeeded checks whether the user requested a relabel -func RelabelNeeded(label string) bool { - return false -} - -// IsShared checks that the label includes a "shared" mark -func IsShared(label string) bool { - return false -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux.go b/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux.go deleted file mode 100644 index e561cbfed7b9d12bec2e8d6dbc6474ea50de3faa..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux.go +++ /dev/null @@ -1,192 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "fmt" - "strings" - - "github.com/opencontainers/runc/libcontainer/selinux" -) - -// Valid Label Options -var validOptions = map[string]bool{ - "disable": true, - "type": true, - "user": true, - "role": true, - "level": true, -} - -var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together") - -// InitLabels returns the process label and file labels to be used within -// the container. A list of options can be passed into this function to alter -// the labels. The labels returned will include a random MCS String, that is -// guaranteed to be unique. -func InitLabels(options []string) (string, string, error) { - if !selinux.SelinuxEnabled() { - return "", "", nil - } - processLabel, mountLabel := selinux.GetLxcContexts() - if processLabel != "" { - pcon := selinux.NewContext(processLabel) - mcon := selinux.NewContext(mountLabel) - for _, opt := range options { - if opt == "disable" { - return "", "", nil - } - if i := strings.Index(opt, ":"); i == -1 { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt) - } - con := strings.SplitN(opt, ":", 2) - if !validOptions[con[0]] { - return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0]) - - } - pcon[con[0]] = con[1] - if con[0] == "level" || con[0] == "user" { - mcon[con[0]] = con[1] - } - } - processLabel = pcon.Get() - mountLabel = mcon.Get() - } - return processLabel, mountLabel, nil -} - -// DEPRECATED: The GenLabels function is only to be used during the transition to the official API. -func GenLabels(options string) (string, string, error) { - return InitLabels(strings.Fields(options)) -} - -// FormatMountLabel returns a string to be used by the mount command. -// The format of this string will be used to alter the labeling of the mountpoint. -// The string returned is suitable to be used as the options field of the mount command. -// If you need to have additional mount point options, you can pass them in as -// the first parameter. Second parameter is the label that you wish to apply -// to all content in the mount point. -func FormatMountLabel(src, mountLabel string) string { - if mountLabel != "" { - switch src { - case "": - src = fmt.Sprintf("context=%q", mountLabel) - default: - src = fmt.Sprintf("%s,context=%q", src, mountLabel) - } - } - return src -} - -// SetProcessLabel takes a process label and tells the kernel to assign the -// label to the next program executed by the current process. -func SetProcessLabel(processLabel string) error { - if processLabel == "" { - return nil - } - return selinux.Setexeccon(processLabel) -} - -// GetProcessLabel returns the process label that the kernel will assign -// to the next program executed by the current process. If "" is returned -// this indicates that the default labeling will happen for the process. -func GetProcessLabel() (string, error) { - return selinux.Getexeccon() -} - -// SetFileLabel modifies the "path" label to the specified file label -func SetFileLabel(path string, fileLabel string) error { - if selinux.SelinuxEnabled() && fileLabel != "" { - return selinux.Setfilecon(path, fileLabel) - } - return nil -} - -// Tell the kernel the label for all files to be created -func SetFileCreateLabel(fileLabel string) error { - if selinux.SelinuxEnabled() { - return selinux.Setfscreatecon(fileLabel) - } - return nil -} - -// Change the label of path to the filelabel string. -// It changes the MCS label to s0 if shared is true. -// This will allow all containers to share the content. -func Relabel(path string, fileLabel string, shared bool) error { - if !selinux.SelinuxEnabled() { - return nil - } - - if fileLabel == "" { - return nil - } - - exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true} - if exclude_paths[path] { - return fmt.Errorf("Relabeling of %s is not allowed", path) - } - - if shared { - c := selinux.NewContext(fileLabel) - c["level"] = "s0" - fileLabel = c.Get() - } - return selinux.Chcon(path, fileLabel, true) -} - -// GetPidLabel will return the label of the process running with the specified pid -func GetPidLabel(pid int) (string, error) { - return selinux.Getpidcon(pid) -} - -// Init initialises the labeling system -func Init() { - selinux.SelinuxEnabled() -} - -// ReserveLabel will record the fact that the MCS label has already been used. -// This will prevent InitLabels from using the MCS label in a newly created -// container -func ReserveLabel(label string) error { - selinux.ReserveLabel(label) - return nil -} - -// UnreserveLabel will remove the reservation of the MCS label. -// This will allow InitLabels to use the MCS label in a newly created -// containers -func UnreserveLabel(label string) error { - selinux.FreeLxcContexts(label) - return nil -} - -// DupSecOpt takes an process label and returns security options that -// can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { - return selinux.DupSecOpt(src) -} - -// DisableSecOpt returns a security opt that can disable labeling -// support for future container processes -func DisableSecOpt() []string { - return selinux.DisableSecOpt() -} - -// Validate checks that the label does not include unexpected options -func Validate(label string) error { - if strings.Contains(label, "z") && strings.Contains(label, "Z") { - return ErrIncompatibleLabel - } - return nil -} - -// RelabelNeeded checks whether the user requested a relabel -func RelabelNeeded(label string) bool { - return strings.Contains(label, "z") || strings.Contains(label, "Z") -} - -// IsShared checks that the label includes a "shared" mark -func IsShared(label string) bool { - return strings.Contains(label, "z") -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go deleted file mode 100644 index c2a19f5b1c503141286e298afef5691ae935a06b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "os" - "strings" - "testing" - - "github.com/opencontainers/runc/libcontainer/selinux" -) - -func TestInit(t *testing.T) { - if selinux.SelinuxEnabled() { - var testNull []string - plabel, mlabel, err := InitLabels(testNull) - if err != nil { - t.Log("InitLabels Failed") - t.Fatal(err) - } - testDisabled := []string{"disable"} - plabel, mlabel, err = InitLabels(testDisabled) - if err != nil { - t.Log("InitLabels Disabled Failed") - t.Fatal(err) - } - if plabel != "" { - t.Log("InitLabels Disabled Failed") - t.Fatal() - } - testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, mlabel, err = InitLabels(testUser) - if err != nil { - t.Log("InitLabels User Failed") - t.Fatal(err) - } - if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" { - t.Log("InitLabels User Match Failed") - t.Log(plabel, mlabel) - t.Fatal(err) - } - - testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, mlabel, err = InitLabels(testBadData) - if err == nil { - t.Log("InitLabels Bad Failed") - t.Fatal(err) - } - } -} -func TestDuplicateLabel(t *testing.T) { - secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2") - t.Log(secopt) - for _, opt := range secopt { - con := strings.SplitN(opt, ":", 3) - if len(con) != 3 || con[0] != "label" { - t.Errorf("Invalid DupSecOpt return value") - continue - } - if con[1] == "user" { - if con[2] != "system_u" { - t.Errorf("DupSecOpt Failed user incorrect") - } - continue - } - if con[1] == "role" { - if con[2] != "system_r" { - t.Errorf("DupSecOpt Failed role incorrect") - } - continue - } - if con[1] == "type" { - if con[2] != "svirt_lxc_net_t" { - t.Errorf("DupSecOpt Failed type incorrect") - } - continue - } - if con[1] == "level" { - if con[2] != "s0:c1,c2" { - t.Errorf("DupSecOpt Failed level incorrect") - } - continue - } - t.Errorf("DupSecOpt Failed invalid field %q", con[1]) - } - secopt = DisableSecOpt() - if secopt[0] != "label:disable" { - t.Errorf("DisableSecOpt Failed level incorrect") - } -} -func TestRelabel(t *testing.T) { - testdir := "/tmp/test" - if err := os.Mkdir(testdir, 0755); err != nil { - t.Fatal(err) - } - defer os.RemoveAll(testdir) - label := "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2" - if err := Relabel(testdir, "", true); err != nil { - t.Fatal("Relabel with no label failed: %v", err) - } - if err := Relabel(testdir, label, true); err != nil { - t.Fatal("Relabel shared failed: %v", err) - } - if err := Relabel(testdir, label, false); err != nil { - t.Fatal("Relabel unshared failed: %v", err) - } - if err := Relabel("/etc", label, false); err == nil { - t.Fatal("Relabel /etc succeeded") - } - if err := Relabel("/", label, false); err == nil { - t.Fatal("Relabel / succeeded") - } - if err := Relabel("/usr", label, false); err == nil { - t.Fatal("Relabel /usr succeeded") - } -} - -func TestValidate(t *testing.T) { - if err := Validate("zZ"); err != ErrIncompatibleLabel { - t.Fatalf("Expected incompatible error, got %v", err) - } - if err := Validate("Z"); err != nil { - t.Fatal(err) - } - if err := Validate("z"); err != nil { - t.Fatal(err) - } - if err := Validate(""); err != nil { - t.Fatal(err) - } -} - -func TestIsShared(t *testing.T) { - if shared := IsShared("Z"); shared { - t.Fatal("Expected label `Z` to not be shared, got %v", shared) - } - if shared := IsShared("z"); !shared { - t.Fatal("Expected label `z` to be shared, got %v", shared) - } - if shared := IsShared("Zz"); !shared { - t.Fatal("Expected label `Zz` to be shared, got %v", shared) - } - -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go index 166301338c1dba9399b30243e6ccb2f1d361f826..1d4f5033aa2f8d447dfcedd72e411791d6580734 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go @@ -3,23 +3,23 @@ package libcontainer import ( - "syscall" - "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" ) // list of known message types we want to send to bootstrap program // The number is randomly chosen to not conflict with known netlink types const ( - InitMsg uint16 = 62000 - CloneFlagsAttr uint16 = 27281 - ConsolePathAttr uint16 = 27282 - NsPathsAttr uint16 = 27283 - UidmapAttr uint16 = 27284 - GidmapAttr uint16 = 27285 - SetgroupAttr uint16 = 27286 - // When syscall.NLA_HDRLEN is in gccgo, take this out. - syscall_NLA_HDRLEN = (syscall.SizeofNlAttr + syscall.NLA_ALIGNTO - 1) & ^(syscall.NLA_ALIGNTO - 1) + InitMsg uint16 = 62000 + CloneFlagsAttr uint16 = 27281 + NsPathsAttr uint16 = 27282 + UidmapAttr uint16 = 27283 + GidmapAttr uint16 = 27284 + SetgroupAttr uint16 = 27285 + OomScoreAdjAttr uint16 = 27286 + RootlessEUIDAttr uint16 = 27287 + UidmapPathAttr uint16 = 27288 + GidmapPathAttr uint16 = 27289 ) type Int32msg struct { @@ -27,7 +27,8 @@ type Int32msg struct { Value uint32 } -// int32msg has the following representation +// Serialize serializes the message. +// Int32msg has the following representation // | nlattr len | nlattr type | // | uint32 value | func (msg *Int32msg) Serialize() []byte { @@ -40,10 +41,10 @@ func (msg *Int32msg) Serialize() []byte { } func (msg *Int32msg) Len() int { - return syscall_NLA_HDRLEN + 4 + return unix.NLA_HDRLEN + 4 } -// bytemsg has the following representation +// Bytemsg has the following representation // | nlattr len | nlattr type | // | value | pad | type Bytemsg struct { @@ -53,7 +54,7 @@ type Bytemsg struct { func (msg *Bytemsg) Serialize() []byte { l := msg.Len() - buf := make([]byte, (l+syscall.NLA_ALIGNTO-1) & ^(syscall.NLA_ALIGNTO-1)) + buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1)) native := nl.NativeEndian() native.PutUint16(buf[0:2], uint16(l)) native.PutUint16(buf[2:4], msg.Type) @@ -62,7 +63,7 @@ func (msg *Bytemsg) Serialize() []byte { } func (msg *Bytemsg) Len() int { - return syscall_NLA_HDRLEN + len(msg.Value) + 1 // null-terminated + return unix.NLA_HDRLEN + len(msg.Value) + 1 // null-terminated } type Boolmsg struct { @@ -76,13 +77,13 @@ func (msg *Boolmsg) Serialize() []byte { native.PutUint16(buf[0:2], uint16(msg.Len())) native.PutUint16(buf[2:4], msg.Type) if msg.Value { - buf[4] = 1 + native.PutUint32(buf[4:8], uint32(1)) } else { - buf[4] = 0 + native.PutUint32(buf[4:8], uint32(0)) } return buf } func (msg *Boolmsg) Len() int { - return syscall_NLA_HDRLEN + 1 + return unix.NLA_HDRLEN + 4 // alignment } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go new file mode 100644 index 0000000000000000000000000000000000000000..e8965e081bb1a95ae688eee9097d6d3250bca1b0 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go @@ -0,0 +1,23 @@ +package mount + +// GetMounts retrieves a list of mounts for the current running process. +func GetMounts() ([]*Info, error) { + return parseMountTable() +} + +// Mounted looks at /proc/self/mountinfo to determine of the specified +// mountpoint has been mounted +func Mounted(mountpoint string) (bool, error) { + entries, err := parseMountTable() + if err != nil { + return false, err + } + + // Search the table for the mountpoint + for _, e := range entries { + if e.Mountpoint == mountpoint { + return true, nil + } + } + return false, nil +} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go similarity index 86% rename from vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_linux.go rename to vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go index be69fee1d7bbf0383ae1c1dd6564652e1cfaa818..1e5191928decfc5e95aa1d9fe0b080274046494c 100644 --- a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go @@ -80,16 +80,3 @@ func parseInfoFile(r io.Reader) ([]*Info, error) { } return out, nil } - -// PidMountInfo collects the mounts for a specific process ID. If the process -// ID is unknown, it is better to use `GetMounts` which will inspect -// "/proc/self/mountinfo" instead. -func PidMountInfo(pid int) ([]*Info, error) { - f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} diff --git a/vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo.go b/vendor/github.com/opencontainers/runc/libcontainer/mount/mountinfo.go similarity index 100% rename from vendor/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/docker/docker/pkg/mount/mountinfo.go rename to vendor/github.com/opencontainers/runc/libcontainer/mount/mountinfo.go diff --git a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go index 5075bee4db5c4d2bdcf5320954c26ae9ce7ca396..569c53f6e8a178090085144cfebf09a6da44fbad 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go @@ -5,18 +5,15 @@ package libcontainer import ( "fmt" "io/ioutil" - "net" "path/filepath" "strconv" "strings" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/utils" "github.com/vishvananda/netlink" ) var strategies = map[string]networkStrategy{ - "veth": &veth{}, "loopback": &loopback{}, } @@ -103,157 +100,3 @@ func (l *loopback) attach(n *configs.Network) (err error) { func (l *loopback) detach(n *configs.Network) (err error) { return nil } - -// veth is a network strategy that uses a bridge and creates -// a veth pair, one that is attached to the bridge on the host and the other -// is placed inside the container's namespace -type veth struct { -} - -func (v *veth) detach(n *configs.Network) (err error) { - return netlink.LinkSetMaster(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil) -} - -// attach a container network interface to an external network -func (v *veth) attach(n *configs.Network) (err error) { - brl, err := netlink.LinkByName(n.Bridge) - if err != nil { - return err - } - br, ok := brl.(*netlink.Bridge) - if !ok { - return fmt.Errorf("Wrong device type %T", brl) - } - host, err := netlink.LinkByName(n.HostInterfaceName) - if err != nil { - return err - } - - if err := netlink.LinkSetMaster(host, br); err != nil { - return err - } - if err := netlink.LinkSetMTU(host, n.Mtu); err != nil { - return err - } - if n.HairpinMode { - if err := netlink.LinkSetHairpin(host, true); err != nil { - return err - } - } - if err := netlink.LinkSetUp(host); err != nil { - return err - } - - return nil -} - -func (v *veth) create(n *network, nspid int) (err error) { - tmpName, err := v.generateTempPeerName() - if err != nil { - return err - } - n.TempVethPeerName = tmpName - if n.Bridge == "" { - return fmt.Errorf("bridge is not specified") - } - veth := &netlink.Veth{ - LinkAttrs: netlink.LinkAttrs{ - Name: n.HostInterfaceName, - TxQLen: n.TxQueueLen, - }, - PeerName: n.TempVethPeerName, - } - if err := netlink.LinkAdd(veth); err != nil { - return err - } - defer func() { - if err != nil { - netlink.LinkDel(veth) - } - }() - if err := v.attach(&n.Network); err != nil { - return err - } - child, err := netlink.LinkByName(n.TempVethPeerName) - if err != nil { - return err - } - return netlink.LinkSetNsPid(child, nspid) -} - -func (v *veth) generateTempPeerName() (string, error) { - return utils.GenerateRandomName("veth", 7) -} - -func (v *veth) initialize(config *network) error { - peer := config.TempVethPeerName - if peer == "" { - return fmt.Errorf("peer is not specified") - } - child, err := netlink.LinkByName(peer) - if err != nil { - return err - } - if err := netlink.LinkSetDown(child); err != nil { - return err - } - if err := netlink.LinkSetName(child, config.Name); err != nil { - return err - } - // get the interface again after we changed the name as the index also changes. - if child, err = netlink.LinkByName(config.Name); err != nil { - return err - } - if config.MacAddress != "" { - mac, err := net.ParseMAC(config.MacAddress) - if err != nil { - return err - } - if err := netlink.LinkSetHardwareAddr(child, mac); err != nil { - return err - } - } - ip, err := netlink.ParseAddr(config.Address) - if err != nil { - return err - } - if err := netlink.AddrAdd(child, ip); err != nil { - return err - } - if config.IPv6Address != "" { - ip6, err := netlink.ParseAddr(config.IPv6Address) - if err != nil { - return err - } - if err := netlink.AddrAdd(child, ip6); err != nil { - return err - } - } - if err := netlink.LinkSetMTU(child, config.Mtu); err != nil { - return err - } - if err := netlink.LinkSetUp(child); err != nil { - return err - } - if config.Gateway != "" { - gw := net.ParseIP(config.Gateway) - if err := netlink.RouteAdd(&netlink.Route{ - Scope: netlink.SCOPE_UNIVERSE, - LinkIndex: child.Attrs().Index, - Gw: gw, - }); err != nil { - return err - } - } - if config.IPv6Gateway != "" { - gw := net.ParseIP(config.IPv6Gateway) - if err := netlink.RouteAdd(&netlink.Route{ - Scope: netlink.SCOPE_UNIVERSE, - LinkIndex: child.Attrs().Index, - Gw: gw, - }); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go index 839a50c55a35a9365f226c35b9a1ec9f44952908..47a06783d6fe546c28dab888867570e547dc14d8 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go @@ -7,7 +7,8 @@ import ( "io/ioutil" "os" "path/filepath" - "syscall" + + "golang.org/x/sys/unix" ) const oomCgroupName = "memory" @@ -25,13 +26,13 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct if err != nil { return nil, err } - fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0) - if syserr != 0 { + fd, err := unix.Eventfd(0, unix.EFD_CLOEXEC) + if err != nil { evFile.Close() - return nil, syserr + return nil, err } - eventfd := os.NewFile(fd, "eventfd") + eventfd := os.NewFile(uintptr(fd), "eventfd") eventControlPath := filepath.Join(cgDir, "cgroup.event_control") data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg) @@ -43,9 +44,9 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct ch := make(chan struct{}) go func() { defer func() { - close(ch) eventfd.Close() evFile.Close() + close(ch) }() buf := make([]byte, 8) for { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_test.go index 9aa4f3b3f46fc88c220e5a186b1386ba3ee4e303..1e15ae2c3b55028865132b2c77f66ec7d519e52e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_test.go @@ -8,9 +8,10 @@ import ( "io/ioutil" "os" "path/filepath" - "syscall" "testing" "time" + + "golang.org/x/sys/unix" ) type notifyFunc func(paths map[string]string) (<-chan struct{}, error) @@ -52,21 +53,17 @@ func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ t.Fatalf("invalid control data %q: %s", data, err) } - // re-open the eventfd - efd, err := syscall.Dup(eventFd) - if err != nil { - t.Fatal("unable to reopen eventfd:", err) - } - defer syscall.Close(efd) - + // dup the eventfd + efd, err := unix.Dup(eventFd) if err != nil { - t.Fatal("unable to dup event fd:", err) + t.Fatal("unable to dup eventfd:", err) } + defer unix.Close(efd) buf := make([]byte, 8) binary.LittleEndian.PutUint64(buf, 1) - if _, err := syscall.Write(efd, buf); err != nil { + if _, err := unix.Write(efd, buf); err != nil { t.Fatal("unable to write to eventfd:", err) } @@ -81,7 +78,7 @@ func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ if err := os.RemoveAll(memoryPath); err != nil { t.Fatal(err) } - if _, err := syscall.Write(efd, buf); err != nil { + if _, err := unix.Write(efd, buf); err != nil { t.Fatal("unable to write to eventfd:", err) } @@ -92,14 +89,15 @@ func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ t.Fatal("expected no notification to be triggered") } case <-time.After(100 * time.Millisecond): + t.Fatal("channel not closed after 100ms") } - if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(evFd), syscall.F_GETFD, 0); err != syscall.EBADF { - t.Error("expected event control to be closed") + if _, _, err := unix.Syscall(unix.SYS_FCNTL, uintptr(evFd), unix.F_GETFD, 0); err != unix.EBADF { + t.Errorf("expected event control to be closed, but received error %s", err.Error()) } - if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(eventFd), syscall.F_GETFD, 0); err != syscall.EBADF { - t.Error("expected event fd to be closed") + if _, _, err := unix.Syscall(unix.SYS_FCNTL, uintptr(eventFd), unix.F_GETFD, 0); err != unix.EBADF { + t.Errorf("expected event fd to be closed, but received error %s", err.Error()) } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/namespace.h b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/namespace.h new file mode 100644 index 0000000000000000000000000000000000000000..9e9bdca05e171cd27a1ba314372ad5af3e621d4d --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/namespace.h @@ -0,0 +1,32 @@ +#ifndef NSENTER_NAMESPACE_H +#define NSENTER_NAMESPACE_H + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include <sched.h> + +/* All of these are taken from include/uapi/linux/sched.h */ +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 /* New mount namespace group */ +#endif +#ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 /* New user namespace */ +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 /* New pid namespace */ +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 /* New network namespace */ +#endif + +#endif /* NSENTER_NAMESPACE_H */ diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go index f7b12be9f840838857af2da32c13ed34a8785133..532155535de3fb17b7dc5d44666ed731006eb517 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_test.go @@ -9,11 +9,12 @@ import ( "os" "os/exec" "strings" - "syscall" "testing" "github.com/opencontainers/runc/libcontainer" "github.com/vishvananda/netlink/nl" + + "golang.org/x/sys/unix" ) type pid struct { @@ -29,7 +30,7 @@ func TestNsenterValidPaths(t *testing.T) { namespaces := []string{ // join pid ns of the current process - fmt.Sprintf("/proc/%d/ns/pid", os.Getpid()), + fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()), } cmd := &exec.Cmd{ Path: os.Args[0], @@ -47,7 +48,7 @@ func TestNsenterValidPaths(t *testing.T) { r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) r.AddData(&libcontainer.Int32msg{ Type: libcontainer.CloneFlagsAttr, - Value: uint32(syscall.CLONE_NEWNET), + Value: uint32(unix.CLONE_NEWNET), }) r.AddData(&libcontainer.Bytemsg{ Type: libcontainer.NsPathsAttr, @@ -60,6 +61,9 @@ func TestNsenterValidPaths(t *testing.T) { decoder := json.NewDecoder(parent) var pid *pid + if err := cmd.Wait(); err != nil { + t.Fatalf("nsenter exits with a non-zero exit status") + } if err := decoder.Decode(&pid); err != nil { dir, _ := ioutil.ReadDir(fmt.Sprintf("/proc/%d/ns", os.Getpid())) for _, d := range dir { @@ -68,9 +72,6 @@ func TestNsenterValidPaths(t *testing.T) { t.Fatalf("%v", err) } - if err := cmd.Wait(); err != nil { - t.Fatalf("nsenter exits with a non-zero exit status") - } p, err := os.FindProcess(pid.Pid) if err != nil { t.Fatalf("%v", err) @@ -87,7 +88,47 @@ func TestNsenterInvalidPaths(t *testing.T) { namespaces := []string{ // join pid ns of the current process - fmt.Sprintf("/proc/%d/ns/pid", -1), + fmt.Sprintf("pid:/proc/%d/ns/pid", -1), + } + cmd := &exec.Cmd{ + Path: os.Args[0], + Args: args, + ExtraFiles: []*os.File{child}, + Env: []string{"_LIBCONTAINER_INITPIPE=3"}, + } + + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + // write cloneFlags + r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) + r.AddData(&libcontainer.Int32msg{ + Type: libcontainer.CloneFlagsAttr, + Value: uint32(unix.CLONE_NEWNET), + }) + r.AddData(&libcontainer.Bytemsg{ + Type: libcontainer.NsPathsAttr, + Value: []byte(strings.Join(namespaces, ",")), + }) + if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil { + t.Fatal(err) + } + + if err := cmd.Wait(); err == nil { + t.Fatalf("nsenter exits with a zero exit status") + } +} + +func TestNsenterIncorrectPathType(t *testing.T) { + args := []string{"nsenter-exec"} + parent, child, err := newPipe() + if err != nil { + t.Fatalf("failed to create pipe %v", err) + } + + namespaces := []string{ + // join pid ns of the current process + fmt.Sprintf("net:/proc/%d/ns/pid", os.Getpid()), } cmd := &exec.Cmd{ Path: os.Args[0], @@ -103,7 +144,7 @@ func TestNsenterInvalidPaths(t *testing.T) { r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0) r.AddData(&libcontainer.Int32msg{ Type: libcontainer.CloneFlagsAttr, - Value: uint32(syscall.CLONE_NEWNET), + Value: uint32(unix.CLONE_NEWNET), }) r.AddData(&libcontainer.Bytemsg{ Type: libcontainer.NsPathsAttr, @@ -126,7 +167,7 @@ func init() { } func newPipe() (parent *os.File, child *os.File, err error) { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0) + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) if err != nil { return nil, nil, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c index a52b7dc37878bc19e2b030f49f3b4e8d5405a6fc..28269dfc027fd4e4315147a5e77da74af969e6a3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c +++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c @@ -1,454 +1,995 @@ + #define _GNU_SOURCE #include <endian.h> #include <errno.h> #include <fcntl.h> -#include <linux/limits.h> -#include <sys/socket.h> -#include <linux/netlink.h> +#include <grp.h> #include <sched.h> #include <setjmp.h> #include <signal.h> +#include <stdarg.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <string.h> +#include <unistd.h> + #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/prctl.h> -#include <unistd.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> -#include <bits/sockaddr.h> +#include <linux/limits.h> +#include <linux/netlink.h> #include <linux/types.h> -// All arguments should be above the stack because it grows down -struct clone_arg { +/* Get all of the CLONE_NEW* flags. */ +#include "namespace.h" + +/* Synchronisation values. */ +enum sync_t { + SYNC_USERMAP_PLS = 0x40, /* Request parent to map our users. */ + SYNC_USERMAP_ACK = 0x41, /* Mapping finished by the parent. */ + SYNC_RECVPID_PLS = 0x42, /* Tell parent we're sending the PID. */ + SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */ + SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */ + SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */ + + /* XXX: This doesn't help with segfaults and other such issues. */ + SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */ +}; + +/* + * Synchronisation value for cgroup namespace setup. + * The same constant is defined in process_linux.go as "createCgroupns". + */ +#define CREATECGROUPNS 0x80 + +/* longjmp() arguments. */ +#define JUMP_PARENT 0x00 +#define JUMP_CHILD 0xA0 +#define JUMP_INIT 0xA1 + +/* JSON buffer. */ +#define JSON_MAX 4096 + +/* Assume the stack grows down, so arguments should be above it. */ +struct clone_t { /* * Reserve some space for clone() to locate arguments * and retcode in this place */ - char stack[4096] __attribute__((aligned(16))); - char stack_ptr[0]; + char stack[4096] __attribute__ ((aligned(16))); + char stack_ptr[0]; + + /* There's two children. This is used to execute the different code. */ jmp_buf *env; + int jmpval; }; -struct nsenter_config { +struct nlconfig_t { + char *data; + + /* Process settings. */ uint32_t cloneflags; - char *uidmap; - int uidmap_len; - char *gidmap; - int gidmap_len; - uint8_t is_setgroup; + char *oom_score_adj; + size_t oom_score_adj_len; + + /* User namespace settings. */ + char *uidmap; + size_t uidmap_len; + char *gidmap; + size_t gidmap_len; + char *namespaces; + size_t namespaces_len; + uint8_t is_setgroup; + + /* Rootless container settings. */ + uint8_t is_rootless_euid; /* boolean */ + char *uidmappath; + size_t uidmappath_len; + char *gidmappath; + size_t gidmappath_len; }; -// list of known message types we want to send to bootstrap program -// These are defined in libcontainer/message_linux.go -#define INIT_MSG 62000 -#define CLONE_FLAGS_ATTR 27281 -#define CONSOLE_PATH_ATTR 27282 -#define NS_PATHS_ATTR 27283 -#define UIDMAP_ATTR 27284 -#define GIDMAP_ATTR 27285 -#define SETGROUP_ATTR 27286 - -// Use raw setns syscall for versions of glibc that don't include it -// (namely glibc-2.12) +/* + * List of netlink message types sent to us as part of bootstrapping the init. + * These constants are defined in libcontainer/message_linux.go. + */ +#define INIT_MSG 62000 +#define CLONE_FLAGS_ATTR 27281 +#define NS_PATHS_ATTR 27282 +#define UIDMAP_ATTR 27283 +#define GIDMAP_ATTR 27284 +#define SETGROUP_ATTR 27285 +#define OOM_SCORE_ADJ_ATTR 27286 +#define ROOTLESS_EUID_ATTR 27287 +#define UIDMAPPATH_ATTR 27288 +#define GIDMAPPATH_ATTR 27289 + +/* + * Use the raw syscall for versions of glibc which don't include a function for + * it, namely (glibc 2.12). + */ #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 14 - #define _GNU_SOURCE - #include "syscall.h" - #if defined(__NR_setns) && !defined(SYS_setns) - #define SYS_setns __NR_setns - #endif - - #ifdef SYS_setns - int setns(int fd, int nstype) - { - return syscall(SYS_setns, fd, nstype); - } - #endif +# define _GNU_SOURCE +# include "syscall.h" +# if !defined(SYS_setns) && defined(__NR_setns) +# define SYS_setns __NR_setns +# endif + +#ifndef SYS_setns +# error "setns(2) syscall not supported by glibc version" #endif -#define pr_perror(fmt, ...) \ - fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__) - -static int child_func(void *_arg) +int setns(int fd, int nstype) { - struct clone_arg *arg = (struct clone_arg *)_arg; - longjmp(*arg->env, 1); + return syscall(SYS_setns, fd, nstype); } +#endif -static int clone_parent(jmp_buf *env, int flags) __attribute__((noinline)); -static int clone_parent(jmp_buf *env, int flags) +/* XXX: This is ugly. */ +static int syncfd = -1; + +/* TODO(cyphar): Fix this so it correctly deals with syncT. */ +#define bail(fmt, ...) \ + do { \ + int ret = __COUNTER__ + 1; \ + fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__); \ + if (syncfd >= 0) { \ + enum sync_t s = SYNC_ERR; \ + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) \ + fprintf(stderr, "nsenter: failed: write(s)"); \ + if (write(syncfd, &ret, sizeof(ret)) != sizeof(ret)) \ + fprintf(stderr, "nsenter: failed: write(ret)"); \ + } \ + exit(ret); \ + } while(0) + +static int write_file(char *data, size_t data_len, char *pathfmt, ...) { - struct clone_arg ca; - int child; - - ca.env = env; - child = clone(child_func, ca.stack_ptr, CLONE_PARENT | SIGCHLD | flags, - &ca); - if (child == -1 && errno == EINVAL) { - if (unshare(flags)) { - pr_perror("Unable to unshare namespaces"); - return -1; - } - child = clone(child_func, ca.stack_ptr, SIGCHLD | CLONE_PARENT, - &ca); + int fd, len, ret = 0; + char path[PATH_MAX]; + + va_list ap; + va_start(ap, pathfmt); + len = vsnprintf(path, PATH_MAX, pathfmt, ap); + va_end(ap); + if (len < 0) + return -1; + + fd = open(path, O_RDWR); + if (fd < 0) { + return -1; + } + + len = write(fd, data, data_len); + if (len != data_len) { + ret = -1; + goto out; } - return child; + + out: + close(fd); + return ret; } -// get init pipe from the parent. It's used to read bootstrap data, and to -// write pid to after nsexec finishes setting up the environment. -static int get_init_pipe() -{ - char buf[PATH_MAX]; - char *initpipe; - int pipenum = -1; +enum policy_t { + SETGROUPS_DEFAULT = 0, + SETGROUPS_ALLOW, + SETGROUPS_DENY, +}; - initpipe = getenv("_LIBCONTAINER_INITPIPE"); - if (initpipe == NULL) { - return -1; +/* This *must* be called before we touch gid_map. */ +static void update_setgroups(int pid, enum policy_t setgroup) +{ + char *policy; + + switch (setgroup) { + case SETGROUPS_ALLOW: + policy = "allow"; + break; + case SETGROUPS_DENY: + policy = "deny"; + break; + case SETGROUPS_DEFAULT: + default: + /* Nothing to do. */ + return; } - pipenum = atoi(initpipe); - snprintf(buf, sizeof(buf), "%d", pipenum); - if (strcmp(initpipe, buf)) { - pr_perror("Unable to parse _LIBCONTAINER_INITPIPE"); - exit(1); + if (write_file(policy, strlen(policy), "/proc/%d/setgroups", pid) < 0) { + /* + * If the kernel is too old to support /proc/pid/setgroups, + * open(2) or write(2) will return ENOENT. This is fine. + */ + if (errno != ENOENT) + bail("failed to write '%s' to /proc/%d/setgroups", policy, pid); } - - return pipenum; } -// num_namespaces returns the number of additional namespaces to setns. The -// argument is a comma-separated string of namespace paths. -static int num_namespaces(char *nspaths) +static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len) { - int i; - int size = 0; + int child; - for (i = 0; nspaths[i]; i++) { - if (nspaths[i] == ',') { - size += 1; + /* + * If @app is NULL, execve will segfault. Just check it here and bail (if + * we're in this path, the caller is already getting desperate and there + * isn't a backup to this failing). This usually would be a configuration + * or programming issue. + */ + if (!app) + bail("mapping tool not present"); + + child = fork(); + if (child < 0) + bail("failed to fork"); + + if (!child) { +#define MAX_ARGV 20 + char *argv[MAX_ARGV]; + char *envp[] = { NULL }; + char pid_fmt[16]; + int argc = 0; + char *next; + + snprintf(pid_fmt, 16, "%d", pid); + + argv[argc++] = (char *)app; + argv[argc++] = pid_fmt; + /* + * Convert the map string into a list of argument that + * newuidmap/newgidmap can understand. + */ + + while (argc < MAX_ARGV) { + if (*map == '\0') { + argv[argc++] = NULL; + break; + } + argv[argc++] = map; + next = strpbrk(map, "\n "); + if (next == NULL) + break; + *next++ = '\0'; + map = next + strspn(next, "\n "); + } + + execve(app, argv, envp); + bail("failed to execv"); + } else { + int status; + + while (true) { + if (waitpid(child, &status, 0) < 0) { + if (errno == EINTR) + continue; + bail("failed to waitpid"); + } + if (WIFEXITED(status) || WIFSIGNALED(status)) + return WEXITSTATUS(status); } } - return size + 1; + return -1; } -static uint32_t readint32(char *buf) +static void update_uidmap(const char *path, int pid, char *map, size_t map_len) { - return *(uint32_t *)buf; + if (map == NULL || map_len <= 0) + return; + + if (write_file(map, map_len, "/proc/%d/uid_map", pid) < 0) { + if (errno != EPERM) + bail("failed to update /proc/%d/uid_map", pid); + if (try_mapping_tool(path, pid, map, map_len)) + bail("failed to use newuid map on %d", pid); + } } -static uint8_t readint8(char *buf) +static void update_gidmap(const char *path, int pid, char *map, size_t map_len) { - return *(uint8_t *)buf; + if (map == NULL || map_len <= 0) + return; + + if (write_file(map, map_len, "/proc/%d/gid_map", pid) < 0) { + if (errno != EPERM) + bail("failed to update /proc/%d/gid_map", pid); + if (try_mapping_tool(path, pid, map, map_len)) + bail("failed to use newgid map on %d", pid); + } } -static void update_process_idmap(char *pathfmt, int pid, char *map, int map_len) +static void update_oom_score_adj(char *data, size_t len) { - char buf[PATH_MAX]; - int len; - int fd; - - len = snprintf(buf, sizeof(buf), pathfmt, pid); - if (len < 0) { - pr_perror("failed to construct '%s' for %d", pathfmt, pid); - exit(1); - } + if (data == NULL || len <= 0) + return; - fd = open(buf, O_RDWR); - if (fd == -1) { - pr_perror("failed to open %s", buf); - exit(1); - } + if (write_file(data, len, "/proc/self/oom_score_adj") < 0) + bail("failed to update /proc/self/oom_score_adj"); +} - len = write(fd, map, map_len); - if (len == -1) { - pr_perror("failed to write to %s", buf); - exit(1); - } else if (len != map_len) { - fprintf(stderr, "Failed to write data to %s (%d/%d)", - buf, len, map_len); - exit(1); - } +/* A dummy function that just jumps to the given jumpval. */ +static int child_func(void *arg) __attribute__ ((noinline)); +static int child_func(void *arg) +{ + struct clone_t *ca = (struct clone_t *)arg; + longjmp(*ca->env, ca->jmpval); +} - close(fd); +static int clone_parent(jmp_buf *env, int jmpval) __attribute__ ((noinline)); +static int clone_parent(jmp_buf *env, int jmpval) +{ + struct clone_t ca = { + .env = env, + .jmpval = jmpval, + }; + + return clone(child_func, ca.stack_ptr, CLONE_PARENT | SIGCHLD, &ca); } -static void update_process_uidmap(int pid, char *map, int map_len) +/* + * Gets the init pipe fd from the environment, which is used to read the + * bootstrap data and tell the parent what the new pid is after we finish + * setting up the environment. + */ +static int initpipe(void) { - if ((map == NULL) || (map_len <= 0)) { - return; - } + int pipenum; + char *initpipe, *endptr; + + initpipe = getenv("_LIBCONTAINER_INITPIPE"); + if (initpipe == NULL || *initpipe == '\0') + return -1; + + pipenum = strtol(initpipe, &endptr, 10); + if (*endptr != '\0') + bail("unable to parse _LIBCONTAINER_INITPIPE"); - update_process_idmap("/proc/%d/uid_map", pid, map, map_len); + return pipenum; } -static void update_process_gidmap(int pid, uint8_t is_setgroup, char *map, int map_len) +/* Returns the clone(2) flag for a namespace, given the name of a namespace. */ +static int nsflag(char *name) { - if ((map == NULL) || (map_len <= 0)) { - return; - } + if (!strcmp(name, "cgroup")) + return CLONE_NEWCGROUP; + else if (!strcmp(name, "ipc")) + return CLONE_NEWIPC; + else if (!strcmp(name, "mnt")) + return CLONE_NEWNS; + else if (!strcmp(name, "net")) + return CLONE_NEWNET; + else if (!strcmp(name, "pid")) + return CLONE_NEWPID; + else if (!strcmp(name, "user")) + return CLONE_NEWUSER; + else if (!strcmp(name, "uts")) + return CLONE_NEWUTS; + + /* If we don't recognise a name, fallback to 0. */ + return 0; +} - if (is_setgroup == 1) { - int fd; - int len; - char buf[PATH_MAX]; +static uint32_t readint32(char *buf) +{ + return *(uint32_t *) buf; +} - len = snprintf(buf, sizeof(buf), "/proc/%d/setgroups", pid); - if (len < 0) { - pr_perror("failed to get setgroups path for %d", pid); - exit(1); - } +static uint8_t readint8(char *buf) +{ + return *(uint8_t *) buf; +} - fd = open(buf, O_RDWR); - if (fd == -1) { - pr_perror("failed to open %s", buf); - exit(1); - } - if (write(fd, "allow", 5) != 5) { - // If the kernel is too old to support - // /proc/PID/setgroups, write will return - // ENOENT; this is OK. - if (errno != ENOENT) { - pr_perror("failed to write allow to %s", buf); - exit(1); - } +static void nl_parse(int fd, struct nlconfig_t *config) +{ + size_t len, size; + struct nlmsghdr hdr; + char *data, *current; + + /* Retrieve the netlink header. */ + len = read(fd, &hdr, NLMSG_HDRLEN); + if (len != NLMSG_HDRLEN) + bail("invalid netlink header length %zu", len); + + if (hdr.nlmsg_type == NLMSG_ERROR) + bail("failed to read netlink message"); + + if (hdr.nlmsg_type != INIT_MSG) + bail("unexpected msg type %d", hdr.nlmsg_type); + + /* Retrieve data. */ + size = NLMSG_PAYLOAD(&hdr, 0); + current = data = malloc(size); + if (!data) + bail("failed to allocate %zu bytes of memory for nl_payload", size); + + len = read(fd, data, size); + if (len != size) + bail("failed to read netlink payload, %zu != %zu", len, size); + + /* Parse the netlink payload. */ + config->data = data; + while (current < data + size) { + struct nlattr *nlattr = (struct nlattr *)current; + size_t payload_len = nlattr->nla_len - NLA_HDRLEN; + + /* Advance to payload. */ + current += NLA_HDRLEN; + + /* Handle payload. */ + switch (nlattr->nla_type) { + case CLONE_FLAGS_ATTR: + config->cloneflags = readint32(current); + break; + case ROOTLESS_EUID_ATTR: + config->is_rootless_euid = readint8(current); /* boolean */ + break; + case OOM_SCORE_ADJ_ATTR: + config->oom_score_adj = current; + config->oom_score_adj_len = payload_len; + break; + case NS_PATHS_ATTR: + config->namespaces = current; + config->namespaces_len = payload_len; + break; + case UIDMAP_ATTR: + config->uidmap = current; + config->uidmap_len = payload_len; + break; + case GIDMAP_ATTR: + config->gidmap = current; + config->gidmap_len = payload_len; + break; + case UIDMAPPATH_ATTR: + config->uidmappath = current; + config->uidmappath_len = payload_len; + break; + case GIDMAPPATH_ATTR: + config->gidmappath = current; + config->gidmappath_len = payload_len; + break; + case SETGROUP_ATTR: + config->is_setgroup = readint8(current); + break; + default: + bail("unknown netlink message type %d", nlattr->nla_type); } - close(fd); - } - update_process_idmap("/proc/%d/gid_map", pid, map, map_len); + current += NLA_ALIGN(payload_len); + } } +void nl_free(struct nlconfig_t *config) +{ + free(config->data); +} -static void start_child(int pipenum, jmp_buf *env, int syncpipe[2], - struct nsenter_config *config) +void join_namespaces(char *nslist) { - int len; - int childpid; - char buf[PATH_MAX]; - uint8_t syncbyte = 1; - - // We must fork to actually enter the PID namespace, use CLONE_PARENT - // so the child can have the right parent, and we don't need to forward - // the child's exit code or resend its death signal. - childpid = clone_parent(env, config->cloneflags); - if (childpid < 0) { - pr_perror("Unable to fork"); - exit(1); - } + int num = 0, i; + char *saveptr = NULL; + char *namespace = strtok_r(nslist, ",", &saveptr); + struct namespace_t { + int fd; + int ns; + char type[PATH_MAX]; + char path[PATH_MAX]; + } *namespaces = NULL; + + if (!namespace || !strlen(namespace) || !strlen(nslist)) + bail("ns paths are empty"); - // update uid_map and gid_map for the child process if they - // were provided - update_process_uidmap(childpid, config->uidmap, config->uidmap_len); + /* + * We have to open the file descriptors first, since after + * we join the mnt namespace we might no longer be able to + * access the paths. + */ + do { + int fd; + char *path; + struct namespace_t *ns; + + /* Resize the namespace array. */ + namespaces = realloc(namespaces, ++num * sizeof(struct namespace_t)); + if (!namespaces) + bail("failed to reallocate namespace array"); + ns = &namespaces[num - 1]; + + /* Split 'ns:path'. */ + path = strstr(namespace, ":"); + if (!path) + bail("failed to parse %s", namespace); + *path++ = '\0'; + + fd = open(path, O_RDONLY); + if (fd < 0) + bail("failed to open %s", path); + + ns->fd = fd; + ns->ns = nsflag(namespace); + strncpy(ns->path, path, PATH_MAX - 1); + ns->path[PATH_MAX - 1] = '\0'; + } while ((namespace = strtok_r(NULL, ",", &saveptr)) != NULL); + + /* + * The ordering in which we join namespaces is important. We should + * always join the user namespace *first*. This is all guaranteed + * from the container_linux.go side of this, so we're just going to + * follow the order given to us. + */ - update_process_gidmap(childpid, config->is_setgroup, config->gidmap, config->gidmap_len); + for (i = 0; i < num; i++) { + struct namespace_t ns = namespaces[i]; - // Send the sync signal to the child - close(syncpipe[0]); - syncbyte = 1; - if (write(syncpipe[1], &syncbyte, 1) != 1) { - pr_perror("failed to write sync byte to child"); - exit(1); - } + if (setns(ns.fd, ns.ns) < 0) + bail("failed to setns to %s", ns.path); - // Send the child pid back to our parent - len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", childpid); - if ((len < 0) || (write(pipenum, buf, len) != len)) { - pr_perror("Unable to send a child pid"); - kill(childpid, SIGKILL); - exit(1); + close(ns.fd); } - exit(0); + free(namespaces); } -static void process_nl_attributes(int pipenum, char *data, int data_size) +void nsexec(void) { - jmp_buf env; - struct nsenter_config config = {0}; - struct nlattr *nlattr; - int payload_len; - int start = 0; - int consolefd = -1; - int syncpipe[2] = {-1, -1}; - - while (start < data_size) { - nlattr = (struct nlattr *)(data + start); - start += NLA_HDRLEN; - payload_len = nlattr->nla_len - NLA_HDRLEN; - - if (nlattr->nla_type == CLONE_FLAGS_ATTR) { - config.cloneflags = readint32(data + start); - } else if (nlattr->nla_type == CONSOLE_PATH_ATTR) { - // get the console path before setns because it may - // change mnt namespace - consolefd = open(data + start, O_RDWR); - if (consolefd < 0) { - pr_perror("Failed to open console %s", - data + start); - exit(1); - } - } else if (nlattr->nla_type == NS_PATHS_ATTR) { - // if custom namespaces are required, open all - // descriptors and perform setns on them - int i; - int nslen = num_namespaces(data + start); - int fds[nslen]; - char *nslist[nslen]; - char *ns; - char *saveptr; - - for (i = 0; i < nslen; i++) { - char *str = NULL; - - if (i == 0) { - str = data + start; - } - ns = strtok_r(str, ",", &saveptr); - if (ns == NULL) { - break; - } - fds[i] = open(ns, O_RDONLY); - if (fds[i] == -1) { - pr_perror("Failed to open %s", ns); - exit(1); - } - nslist[i] = ns; - } + int pipenum; + jmp_buf env; + int sync_child_pipe[2], sync_grandchild_pipe[2]; + struct nlconfig_t config = { 0 }; + + /* + * If we don't have an init pipe, just return to the go routine. + * We'll only get an init pipe for start or exec. + */ + pipenum = initpipe(); + if (pipenum == -1) + return; + + /* Parse all of the netlink configuration. */ + nl_parse(pipenum, &config); + + /* Set oom_score_adj. This has to be done before !dumpable because + * /proc/self/oom_score_adj is not writeable unless you're an privileged + * user (if !dumpable is set). All children inherit their parent's + * oom_score_adj value on fork(2) so this will always be propagated + * properly. + */ + update_oom_score_adj(config.oom_score_adj, config.oom_score_adj_len); + + /* + * Make the process non-dumpable, to avoid various race conditions that + * could cause processes in namespaces we're joining to access host + * resources (or potentially execute code). + * + * However, if the number of namespaces we are joining is 0, we are not + * going to be switching to a different security context. Thus setting + * ourselves to be non-dumpable only breaks things (like rootless + * containers), which is the recommendation from the kernel folks. + */ + if (config.namespaces) { + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) < 0) + bail("failed to set process as non-dumpable"); + } + + /* Pipe so we can tell the child when we've finished setting up. */ + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sync_child_pipe) < 0) + bail("failed to setup sync pipe between parent and child"); + + /* + * We need a new socketpair to sync with grandchild so we don't have + * race condition with child. + */ + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sync_grandchild_pipe) < 0) + bail("failed to setup sync pipe between parent and grandchild"); - for (i = 0; i < nslen; i++) { - if (setns(fds[i], 0) != 0) { - pr_perror("Failed to setns to %s", nslist[i]); - exit(1); + /* TODO: Currently we aren't dealing with child deaths properly. */ + + /* + * Okay, so this is quite annoying. + * + * In order for this unsharing code to be more extensible we need to split + * up unshare(CLONE_NEWUSER) and clone() in various ways. The ideal case + * would be if we did clone(CLONE_NEWUSER) and the other namespaces + * separately, but because of SELinux issues we cannot really do that. But + * we cannot just dump the namespace flags into clone(...) because several + * usecases (such as rootless containers) require more granularity around + * the namespace setup. In addition, some older kernels had issues where + * CLONE_NEWUSER wasn't handled before other namespaces (but we cannot + * handle this while also dealing with SELinux so we choose SELinux support + * over broken kernel support). + * + * However, if we unshare(2) the user namespace *before* we clone(2), then + * all hell breaks loose. + * + * The parent no longer has permissions to do many things (unshare(2) drops + * all capabilities in your old namespace), and the container cannot be set + * up to have more than one {uid,gid} mapping. This is obviously less than + * ideal. In order to fix this, we have to first clone(2) and then unshare. + * + * Unfortunately, it's not as simple as that. We have to fork to enter the + * PID namespace (the PID namespace only applies to children). Since we'll + * have to double-fork, this clone_parent() call won't be able to get the + * PID of the _actual_ init process (without doing more synchronisation than + * I can deal with at the moment). So we'll just get the parent to send it + * for us, the only job of this process is to update + * /proc/pid/{setgroups,uid_map,gid_map}. + * + * And as a result of the above, we also need to setns(2) in the first child + * because if we join a PID namespace in the topmost parent then our child + * will be in that namespace (and it will not be able to give us a PID value + * that makes sense without resorting to sending things with cmsg). + * + * This also deals with an older issue caused by dumping cloneflags into + * clone(2): On old kernels, CLONE_PARENT didn't work with CLONE_NEWPID, so + * we have to unshare(2) before clone(2) in order to do this. This was fixed + * in upstream commit 1f7f4dde5c945f41a7abc2285be43d918029ecc5, and was + * introduced by 40a0d32d1eaffe6aac7324ca92604b6b3977eb0e. As far as we're + * aware, the last mainline kernel which had this bug was Linux 3.12. + * However, we cannot comment on which kernels the broken patch was + * backported to. + * + * -- Aleksa "what has my life come to?" Sarai + */ + + switch (setjmp(env)) { + /* + * Stage 0: We're in the parent. Our job is just to create a new child + * (stage 1: JUMP_CHILD) process and write its uid_map and + * gid_map. That process will go on to create a new process, then + * it will send us its PID which we will send to the bootstrap + * process. + */ + case JUMP_PARENT:{ + int len; + pid_t child, first_child = -1; + bool ready = false; + + /* For debugging. */ + prctl(PR_SET_NAME, (unsigned long)"runc:[0:PARENT]", 0, 0, 0); + + /* Start the process of getting a container. */ + child = clone_parent(&env, JUMP_CHILD); + if (child < 0) + bail("unable to fork: child_func"); + + /* + * State machine for synchronisation with the children. + * + * Father only return when both child and grandchild are + * ready, so we can receive all possible error codes + * generated by children. + */ + while (!ready) { + enum sync_t s; + int ret; + + syncfd = sync_child_pipe[1]; + close(sync_child_pipe[0]); + + if (read(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with child: next state"); + + switch (s) { + case SYNC_ERR: + /* We have to mirror the error code of the child. */ + if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret)) + bail("failed to sync with child: read(error code)"); + + exit(ret); + case SYNC_USERMAP_PLS: + /* + * Enable setgroups(2) if we've been asked to. But we also + * have to explicitly disable setgroups(2) if we're + * creating a rootless container for single-entry mapping. + * i.e. config.is_setgroup == false. + * (this is required since Linux 3.19). + * + * For rootless multi-entry mapping, config.is_setgroup shall be true and + * newuidmap/newgidmap shall be used. + */ + + if (config.is_rootless_euid && !config.is_setgroup) + update_setgroups(child, SETGROUPS_DENY); + + /* Set up mappings. */ + update_uidmap(config.uidmappath, child, config.uidmap, config.uidmap_len); + update_gidmap(config.gidmappath, child, config.gidmap, config.gidmap_len); + + s = SYNC_USERMAP_ACK; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(child, SIGKILL); + bail("failed to sync with child: write(SYNC_USERMAP_ACK)"); + } + break; + case SYNC_RECVPID_PLS:{ + first_child = child; + + /* Get the init_func pid. */ + if (read(syncfd, &child, sizeof(child)) != sizeof(child)) { + kill(first_child, SIGKILL); + bail("failed to sync with child: read(childpid)"); + } + + /* Send ACK. */ + s = SYNC_RECVPID_ACK; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(first_child, SIGKILL); + kill(child, SIGKILL); + bail("failed to sync with child: write(SYNC_RECVPID_ACK)"); + } + + /* Send the init_func pid back to our parent. + * + * Send the init_func pid and the pid of the first child back to our parent. + * We need to send both back because we can't reap the first child we created (CLONE_PARENT). + * It becomes the responsibility of our parent to reap the first child. + */ + len = dprintf(pipenum, "{\"pid\": %d, \"pid_first\": %d}\n", child, first_child); + if (len < 0) { + kill(child, SIGKILL); + bail("unable to generate JSON for child pid"); + } + } + break; + case SYNC_CHILD_READY: + ready = true; + break; + default: + bail("unexpected sync value: %u", s); } - close(fds[i]); } - } else if (nlattr->nla_type == UIDMAP_ATTR) { - config.uidmap = data + start; - config.uidmap_len = payload_len; - } else if (nlattr->nla_type == GIDMAP_ATTR) { - config.gidmap = data + start; - config.gidmap_len = payload_len; - } else if (nlattr->nla_type == SETGROUP_ATTR) { - config.is_setgroup = readint8(data + start); - } else { - pr_perror("Unknown netlink message type %d", - nlattr->nla_type); - exit(1); - } - start += NLA_ALIGN(payload_len); - } + /* Now sync with grandchild. */ - // required clone_flags to be passed - if (config.cloneflags == -1) { - pr_perror("Missing clone_flags"); - exit(1); - } - // prepare sync pipe between parent and child. We need this to let the - // child - // know that the parent has finished setting up - if (pipe(syncpipe) != 0) { - pr_perror("Failed to setup sync pipe between parent and child"); - exit(1); - } + ready = false; + while (!ready) { + enum sync_t s; + int ret; - if (setjmp(env) == 1) { - // Child - uint8_t s = 0; + syncfd = sync_grandchild_pipe[1]; + close(sync_grandchild_pipe[0]); - // close the writing side of pipe - close(syncpipe[1]); + s = SYNC_GRANDCHILD; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(child, SIGKILL); + bail("failed to sync with child: write(SYNC_GRANDCHILD)"); + } - // sync with parent - if ((read(syncpipe[0], &s, 1) != 1) || (s != 1)) { - pr_perror("Failed to read sync byte from parent"); - exit(1); - } + if (read(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with child: next state"); - if (setsid() == -1) { - pr_perror("setsid failed"); - exit(1); - } + switch (s) { + case SYNC_ERR: + /* We have to mirror the error code of the child. */ + if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret)) + bail("failed to sync with child: read(error code)"); - if (setuid(0) == -1) { - pr_perror("setuid failed"); - exit(1); + exit(ret); + case SYNC_CHILD_READY: + ready = true; + break; + default: + bail("unexpected sync value: %u", s); + } + } + exit(0); } - if (setgid(0) == -1) { - pr_perror("setgid failed"); - exit(1); - } + /* + * Stage 1: We're in the first child process. Our job is to join any + * provided namespaces in the netlink payload and unshare all + * of the requested namespaces. If we've been asked to + * CLONE_NEWUSER, we will ask our parent (stage 0) to set up + * our user mappings for us. Then, we create a new child + * (stage 2: JUMP_INIT) for PID namespace. We then send the + * child's PID to our parent (stage 0). + */ + case JUMP_CHILD:{ + pid_t child; + enum sync_t s; + + /* We're in a child and thus need to tell the parent if we die. */ + syncfd = sync_child_pipe[0]; + close(sync_child_pipe[1]); + + /* For debugging. */ + prctl(PR_SET_NAME, (unsigned long)"runc:[1:CHILD]", 0, 0, 0); + + /* + * We need to setns first. We cannot do this earlier (in stage 0) + * because of the fact that we forked to get here (the PID of + * [stage 2: JUMP_INIT]) would be meaningless). We could send it + * using cmsg(3) but that's just annoying. + */ + if (config.namespaces) + join_namespaces(config.namespaces); + + /* + * Deal with user namespaces first. They are quite special, as they + * affect our ability to unshare other namespaces and are used as + * context for privilege checks. + * + * We don't unshare all namespaces in one go. The reason for this + * is that, while the kernel documentation may claim otherwise, + * there are certain cases where unsharing all namespaces at once + * will result in namespace objects being owned incorrectly. + * Ideally we should just fix these kernel bugs, but it's better to + * be safe than sorry, and fix them separately. + * + * A specific case of this is that the SELinux label of the + * internal kern-mount that mqueue uses will be incorrect if the + * UTS namespace is cloned before the USER namespace is mapped. + * I've also heard of similar problems with the network namespace + * in some scenarios. This also mirrors how LXC deals with this + * problem. + */ + if (config.cloneflags & CLONE_NEWUSER) { + if (unshare(CLONE_NEWUSER) < 0) + bail("failed to unshare user namespace"); + config.cloneflags &= ~CLONE_NEWUSER; + + /* + * We don't have the privileges to do any mapping here (see the + * clone_parent rant). So signal our parent to hook us up. + */ + + /* Switching is only necessary if we joined namespaces. */ + if (config.namespaces) { + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) + bail("failed to set process as dumpable"); + } + s = SYNC_USERMAP_PLS; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with parent: write(SYNC_USERMAP_PLS)"); + + /* ... wait for mapping ... */ + + if (read(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with parent: read(SYNC_USERMAP_ACK)"); + if (s != SYNC_USERMAP_ACK) + bail("failed to sync with parent: SYNC_USERMAP_ACK: got %u", s); + /* Switching is only necessary if we joined namespaces. */ + if (config.namespaces) { + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) < 0) + bail("failed to set process as dumpable"); + } - if (consolefd != -1) { - if (ioctl(consolefd, TIOCSCTTY, 0) == -1) { - pr_perror("ioctl TIOCSCTTY failed"); - exit(1); + /* Become root in the namespace proper. */ + if (setresuid(0, 0, 0) < 0) + bail("failed to become root in user namespace"); } - if (dup3(consolefd, STDIN_FILENO, 0) != STDIN_FILENO) { - pr_perror("Failed to dup stdin"); - exit(1); + /* + * Unshare all of the namespaces. Now, it should be noted that this + * ordering might break in the future (especially with rootless + * containers). But for now, it's not possible to split this into + * CLONE_NEWUSER + [the rest] because of some RHEL SELinux issues. + * + * Note that we don't merge this with clone() because there were + * some old kernel versions where clone(CLONE_PARENT | CLONE_NEWPID) + * was broken, so we'll just do it the long way anyway. + */ + if (unshare(config.cloneflags & ~CLONE_NEWCGROUP) < 0) + bail("failed to unshare namespaces"); + + /* + * TODO: What about non-namespace clone flags that we're dropping here? + * + * We fork again because of PID namespace, setns(2) or unshare(2) don't + * change the PID namespace of the calling process, because doing so + * would change the caller's idea of its own PID (as reported by getpid()), + * which would break many applications and libraries, so we must fork + * to actually enter the new PID namespace. + */ + child = clone_parent(&env, JUMP_INIT); + if (child < 0) + bail("unable to fork: init_func"); + + /* Send the child to our parent, which knows what it's doing. */ + s = SYNC_RECVPID_PLS; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(child, SIGKILL); + bail("failed to sync with parent: write(SYNC_RECVPID_PLS)"); } - if (dup3(consolefd, STDOUT_FILENO, 0) != STDOUT_FILENO) { - pr_perror("Failed to dup stdout"); - exit(1); + if (write(syncfd, &child, sizeof(child)) != sizeof(child)) { + kill(child, SIGKILL); + bail("failed to sync with parent: write(childpid)"); } - if (dup3(consolefd, STDERR_FILENO, 0) != STDERR_FILENO) { - pr_perror("Failed to dup stderr"); - exit(1); - } - } - // Finish executing, let the Go runtime take over. - return; - } + /* ... wait for parent to get the pid ... */ - // Parent - start_child(pipenum, &env, syncpipe, &config); -} + if (read(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(child, SIGKILL); + bail("failed to sync with parent: read(SYNC_RECVPID_ACK)"); + } + if (s != SYNC_RECVPID_ACK) { + kill(child, SIGKILL); + bail("failed to sync with parent: SYNC_RECVPID_ACK: got %u", s); + } -void nsexec(void) -{ - int pipenum; + s = SYNC_CHILD_READY; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { + kill(child, SIGKILL); + bail("failed to sync with parent: write(SYNC_CHILD_READY)"); + } - // if we dont have init pipe, then just return to the parent - pipenum = get_init_pipe(); - if (pipenum == -1) { - return; - } + /* Our work is done. [Stage 2: JUMP_INIT] is doing the rest of the work. */ + exit(0); + } - // Retrieve the netlink header - struct nlmsghdr nl_msg_hdr; - int len; + /* + * Stage 2: We're the final child process, and the only process that will + * actually return to the Go runtime. Our job is to just do the + * final cleanup steps and then return to the Go runtime to allow + * init_linux.go to run. + */ + case JUMP_INIT:{ + /* + * We're inside the child now, having jumped from the + * start_child() code after forking in the parent. + */ + enum sync_t s; + + /* We're in a child and thus need to tell the parent if we die. */ + syncfd = sync_grandchild_pipe[0]; + close(sync_grandchild_pipe[1]); + close(sync_child_pipe[0]); + close(sync_child_pipe[1]); + + /* For debugging. */ + prctl(PR_SET_NAME, (unsigned long)"runc:[2:INIT]", 0, 0, 0); + + if (read(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with parent: read(SYNC_GRANDCHILD)"); + if (s != SYNC_GRANDCHILD) + bail("failed to sync with parent: SYNC_GRANDCHILD: got %u", s); + + if (setsid() < 0) + bail("setsid failed"); + + if (setuid(0) < 0) + bail("setuid failed"); + + if (setgid(0) < 0) + bail("setgid failed"); + + if (!config.is_rootless_euid && config.is_setgroup) { + if (setgroups(0, NULL) < 0) + bail("setgroups failed"); + } - if ((len = read(pipenum, &nl_msg_hdr, NLMSG_HDRLEN)) != NLMSG_HDRLEN) { - pr_perror("Invalid netlink header length %d", len); - exit(1); - } + /* ... wait until our topmost parent has finished cgroup setup in p.manager.Apply() ... */ + if (config.cloneflags & CLONE_NEWCGROUP) { + uint8_t value; + if (read(pipenum, &value, sizeof(value)) != sizeof(value)) + bail("read synchronisation value failed"); + if (value == CREATECGROUPNS) { + if (unshare(CLONE_NEWCGROUP) < 0) + bail("failed to unshare cgroup namespace"); + } else + bail("received unknown synchronisation value"); + } - if (nl_msg_hdr.nlmsg_type == NLMSG_ERROR) { - pr_perror("Failed to read netlink message"); - exit(1); - } + s = SYNC_CHILD_READY; + if (write(syncfd, &s, sizeof(s)) != sizeof(s)) + bail("failed to sync with patent: write(SYNC_CHILD_READY)"); - if (nl_msg_hdr.nlmsg_type != INIT_MSG) { - pr_perror("Unexpected msg type %d", nl_msg_hdr.nlmsg_type); - exit(1); - } + /* Close sync pipes. */ + close(sync_grandchild_pipe[0]); - // Retrieve data - int nl_total_size = NLMSG_PAYLOAD(&nl_msg_hdr, 0); - char data[nl_total_size]; + /* Free netlink data. */ + nl_free(&config); - if ((len = read(pipenum, data, nl_total_size)) != nl_total_size) { - pr_perror("Failed to read netlink payload, %d != %d", len, - nl_total_size); - exit(1); + /* Finish executing, let the Go runtime take over. */ + return; + } + default: + bail("unexpected jump value"); } - process_nl_attributes(pipenum, data, nl_total_size); + /* Should never be reached. */ + bail("should never be reached"); } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process.go b/vendor/github.com/opencontainers/runc/libcontainer/process.go index 91e8ef56f7e614b16e9bfcfbb85f0699b7b5743c..9a7c60141216fba9b024da83f42424610c84cd46 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process.go @@ -28,6 +28,10 @@ type Process struct { // local to the container's user and group configuration. User string + // AdditionalGroups specifies the gids that should be added to supplementary groups + // in addition to those that the user belongs to. + AdditionalGroups []string + // Cwd will change the processes current working directory inside the container's rootfs. Cwd string @@ -43,12 +47,13 @@ type Process struct { // ExtraFiles specifies additional open files to be inherited by the container ExtraFiles []*os.File - // consolePath is the path to the console allocated to the container. - consolePath string + // Initial sizings for the console + ConsoleWidth uint16 + ConsoleHeight uint16 // Capabilities specify the capabilities to keep when executing the process inside the container // All capabilities not specified will be dropped from the processes capability mask - Capabilities []string + Capabilities *configs.Capabilities // AppArmorProfile specifies the profile to apply to the process and is // changed at the time the process is execed @@ -64,6 +69,12 @@ type Process struct { // If Rlimits are not set, the container will inherit rlimits from the parent process Rlimits []configs.Rlimit + // ConsoleSocket provides the masterfd console. + ConsoleSocket *os.File + + // Init specifies whether the process is the first process in the container. + Init bool + ops processOperations } @@ -100,22 +111,3 @@ type IO struct { Stdout io.ReadCloser Stderr io.ReadCloser } - -// NewConsole creates new console for process and returns it -func (p *Process) NewConsole(rootuid int) (Console, error) { - console, err := NewConsole(rootuid, rootuid) - if err != nil { - return nil, err - } - p.consolePath = console.Path() - return console, nil -} - -// ConsoleFromPath sets the process's console with the path provided -func (p *Process) ConsoleFromPath(path string) error { - if p.consolePath != "" { - return newGenericError(fmt.Errorf("console path already exists for process"), ConsoleExists) - } - p.consolePath = path - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go index 9ff43861512a44efdc44ad75d642b61ceb1dea4d..e8ffac9fa58cacf7ddf0e4beb2886ae97da72bd3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -11,14 +11,21 @@ import ( "os/exec" "path/filepath" "strconv" - "syscall" + "syscall" // only for Signal "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/utils" + + "golang.org/x/sys/unix" ) +// Synchronisation value for cgroup namespace setup. +// The same constant is defined in nsexec.c as "CREATECGROUPNS". +const createCgroupns = 0x80 + type parentProcess interface { // pid returns the pid for the running process. pid() int @@ -32,8 +39,8 @@ type parentProcess interface { // wait waits on the process returning the process state. wait() (*os.ProcessState, error) - // startTime return's the process start time. - startTime() (string, error) + // startTime returns the process start time. + startTime() (uint64, error) signal(os.Signal) error @@ -43,18 +50,21 @@ type parentProcess interface { } type setnsProcess struct { - cmd *exec.Cmd - parentPipe *os.File - childPipe *os.File - cgroupPaths map[string]string - config *initConfig - fds []string - process *Process - bootstrapData io.Reader + cmd *exec.Cmd + parentPipe *os.File + childPipe *os.File + cgroupPaths map[string]string + rootlessCgroups bool + intelRdtPath string + config *initConfig + fds []string + process *Process + bootstrapData io.Reader } -func (p *setnsProcess) startTime() (string, error) { - return system.GetProcessStartTime(p.pid()) +func (p *setnsProcess) startTime() (uint64, error) { + stat, err := system.Stat(p.pid()) + return stat.StartTime, err } func (p *setnsProcess) signal(sig os.Signal) error { @@ -62,7 +72,7 @@ func (p *setnsProcess) signal(sig os.Signal) error { if !ok { return errors.New("os: unsupported signal type") } - return syscall.Kill(p.pid(), s) + return unix.Kill(p.pid(), s) } func (p *setnsProcess) start() (err error) { @@ -70,42 +80,59 @@ func (p *setnsProcess) start() (err error) { err = p.cmd.Start() p.childPipe.Close() if err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "starting setns process") } if p.bootstrapData != nil { if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "copying bootstrap data to pipe") } } if err = p.execSetns(); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "executing setns process") } if len(p.cgroupPaths) > 0 { - if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil { - return newSystemError(err) + if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil && !p.rootlessCgroups { + return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid()) } } - if err := utils.WriteJSON(p.parentPipe, p.config); err != nil { - return newSystemError(err) + if p.intelRdtPath != "" { + // if Intel RDT "resource control" filesystem path exists + _, err := os.Stat(p.intelRdtPath) + if err == nil { + if err := intelrdt.WriteIntelRdtTasks(p.intelRdtPath, p.pid()); err != nil { + return newSystemErrorWithCausef(err, "adding pid %d to Intel RDT resource control filesystem", p.pid()) + } + } } - // set oom_score_adj - if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil { - return newSystemError(err) + // set rlimits, this has to be done here because we lose permissions + // to raise the limits once we enter a user-namespace + if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { + return newSystemErrorWithCause(err, "setting rlimits for process") } - - if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil { - return newSystemError(err) + if err := utils.WriteJSON(p.parentPipe, p.config); err != nil { + return newSystemErrorWithCause(err, "writing config to pipe") } - // wait for the child process to fully complete and receive an error message - // if one was encoutered - var ierr *genericError - if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF { - return newSystemError(err) + + ierr := parseSync(p.parentPipe, func(sync *syncT) error { + switch sync.Type { + case procReady: + // This shouldn't happen. + panic("unexpected procReady in setns") + case procHooks: + // This shouldn't happen. + panic("unexpected procHooks in setns") + default: + return newSystemError(fmt.Errorf("invalid JSON payload from child")) + } + }) + + if err := unix.Shutdown(int(p.parentPipe.Fd()), unix.SHUT_WR); err != nil { + return newSystemErrorWithCause(err, "calling shutdown on init pipe") } // Must be done after Shutdown so the child will exit and we can wait for it. if ierr != nil { p.wait() - return newSystemError(ierr) + return ierr } return nil } @@ -118,7 +145,7 @@ func (p *setnsProcess) execSetns() error { status, err := p.cmd.Process.Wait() if err != nil { p.cmd.Wait() - return newSystemError(err) + return newSystemErrorWithCause(err, "waiting on setns process to finish") } if !status.Success() { p.cmd.Wait() @@ -127,8 +154,18 @@ func (p *setnsProcess) execSetns() error { var pid *pid if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { p.cmd.Wait() - return newSystemError(err) + return newSystemErrorWithCause(err, "reading pid from init pipe") + } + + // Clean up the zombie parent process + firstChildProcess, err := os.FindProcess(pid.PidFirstChild) + if err != nil { + return err } + + // Ignore the error in case the child has already been reaped for any reason + _, _ = firstChildProcess.Wait() + process, err := os.FindProcess(pid.Pid) if err != nil { return err @@ -139,7 +176,7 @@ func (p *setnsProcess) execSetns() error { } // terminate sends a SIGKILL to the forked process for the setns routine then waits to -// avoid the process becomming a zombie. +// avoid the process becoming a zombie. func (p *setnsProcess) terminate() error { if p.cmd.Process == nil { return nil @@ -171,16 +208,17 @@ func (p *setnsProcess) setExternalDescriptors(newFds []string) { } type initProcess struct { - cmd *exec.Cmd - parentPipe *os.File - childPipe *os.File - config *initConfig - manager cgroups.Manager - container *linuxContainer - fds []string - process *Process - bootstrapData io.Reader - sharePidns bool + cmd *exec.Cmd + parentPipe *os.File + childPipe *os.File + config *initConfig + manager cgroups.Manager + intelRdtManager intelrdt.Manager + container *linuxContainer + fds []string + process *Process + bootstrapData io.Reader + sharePidns bool } func (p *initProcess) pid() int { @@ -191,12 +229,17 @@ func (p *initProcess) externalDescriptors() []string { return p.fds } -// execSetns runs the process that executes C code to perform the setns calls -// because setns support requires the C process to fork off a child and perform the setns -// before the go runtime boots, we wait on the process to die and receive the child's pid -// over the provided pipe. -// This is called by initProcess.start function -func (p *initProcess) execSetns() error { +// getChildPid receives the final child's pid over the provided pipe. +func (p *initProcess) getChildPid() (int, error) { + var pid pid + if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { + p.cmd.Wait() + return -1, err + } + return pid.Pid, nil +} + +func (p *initProcess) waitForChildExit(childPid int) error { status, err := p.cmd.Process.Wait() if err != nil { p.cmd.Wait() @@ -206,16 +249,13 @@ func (p *initProcess) execSetns() error { p.cmd.Wait() return &exec.ExitError{ProcessState: status} } - var pid *pid - if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil { - p.cmd.Wait() - return err - } - process, err := os.FindProcess(pid.Pid) + + process, err := os.FindProcess(childPid) if err != nil { return err } p.cmd.Process = process + p.process.ops = p return nil } @@ -226,27 +266,67 @@ func (p *initProcess) start() error { p.childPipe.Close() if err != nil { p.process.ops = nil - return newSystemError(err) + return newSystemErrorWithCause(err, "starting init process command") + } + // Do this before syncing with child so that no children can escape the + // cgroup. We don't need to worry about not doing this and not being root + // because we'd be using the rootless cgroup manager in that case. + if err := p.manager.Apply(p.pid()); err != nil { + return newSystemErrorWithCause(err, "applying cgroup configuration for process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Apply(p.pid()); err != nil { + return newSystemErrorWithCause(err, "applying Intel RDT configuration for process") + } } + defer func() { + if err != nil { + // TODO: should not be the responsibility to call here + p.manager.Destroy() + if p.intelRdtManager != nil { + p.intelRdtManager.Destroy() + } + } + }() + if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil { - return err + return newSystemErrorWithCause(err, "copying bootstrap data to pipe") } - if err := p.execSetns(); err != nil { - return newSystemError(err) + childPid, err := p.getChildPid() + if err != nil { + return newSystemErrorWithCause(err, "getting the final child's pid from pipe") } + // Save the standard descriptor names before the container process // can potentially move them (e.g., via dup2()). If we don't do this now, // we won't know at checkpoint time which file descriptor to look up. - fds, err := getPipeFds(p.pid()) + fds, err := getPipeFds(childPid) if err != nil { - return newSystemError(err) + return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", childPid) } p.setExternalDescriptors(fds) // Do this before syncing with child so that no children // can escape the cgroup - if err := p.manager.Apply(p.pid()); err != nil { - return newSystemError(err) + if err := p.manager.Apply(childPid); err != nil { + return newSystemErrorWithCause(err, "applying cgroup configuration for process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Apply(childPid); err != nil { + return newSystemErrorWithCause(err, "applying Intel RDT configuration for process") + } + } + // Now it's time to setup cgroup namesapce + if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" { + if _, err := p.parentPipe.Write([]byte{createCgroupns}); err != nil { + return newSystemErrorWithCause(err, "sending synchronization value to init process") + } + } + + // Wait for our first child to exit + if err := p.waitForChildExit(childPid); err != nil { + return newSystemErrorWithCause(err, "waiting for our first child to exit") } + defer func() { if err != nil { // TODO: should not be the responsibility to call here @@ -254,104 +334,106 @@ func (p *initProcess) start() error { } }() if err := p.createNetworkInterfaces(); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "creating network interfaces") } if err := p.sendConfig(); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "sending config to init process") } var ( - procSync syncT sentRun bool sentResume bool - ierr *genericError ) - dec := json.NewDecoder(p.parentPipe) -loop: - for { - if err := dec.Decode(&procSync); err != nil { - if err == io.EOF { - break loop - } - return newSystemError(err) - } - switch procSync.Type { + ierr := parseSync(p.parentPipe, func(sync *syncT) error { + switch sync.Type { case procReady: - if err := p.manager.Set(p.config.Config); err != nil { - return newSystemError(err) - } - // set oom_score_adj - if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil { - return newSystemError(err) + // set rlimits, this has to be done here because we lose permissions + // to raise the limits once we enter a user-namespace + if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { + return newSystemErrorWithCause(err, "setting rlimits for ready process") } // call prestart hooks if !p.config.Config.Namespaces.Contains(configs.NEWNS) { + // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions. + if err := p.manager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting cgroup config for ready process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting Intel RDT config for ready process") + } + } + if p.config.Config.Hooks != nil { - s := configs.HookState{ - Version: p.container.config.Version, - ID: p.container.id, - Pid: p.pid(), - Root: p.config.Config.Rootfs, + s, err := p.container.currentOCIState() + if err != nil { + return err } - for _, hook := range p.config.Config.Hooks.Prestart { + // initProcessStartTime hasn't been set yet. + s.Pid = p.cmd.Process.Pid + s.Status = "creating" + for i, hook := range p.config.Config.Hooks.Prestart { if err := hook.Run(s); err != nil { - return newSystemError(err) + return newSystemErrorWithCausef(err, "running prestart hook %d", i) } } } } // Sync with child. - if err := utils.WriteJSON(p.parentPipe, syncT{procRun}); err != nil { - return newSystemError(err) + if err := writeSync(p.parentPipe, procRun); err != nil { + return newSystemErrorWithCause(err, "writing syncT 'run'") } sentRun = true case procHooks: + // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions. + if err := p.manager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting cgroup config for procHooks process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting Intel RDT config for procHooks process") + } + } if p.config.Config.Hooks != nil { - s := configs.HookState{ - Version: p.container.config.Version, - ID: p.container.id, - Pid: p.pid(), - Root: p.config.Config.Rootfs, + s, err := p.container.currentOCIState() + if err != nil { + return err } - for _, hook := range p.config.Config.Hooks.Prestart { + // initProcessStartTime hasn't been set yet. + s.Pid = p.cmd.Process.Pid + s.Status = "creating" + for i, hook := range p.config.Config.Hooks.Prestart { if err := hook.Run(s); err != nil { - return newSystemError(err) + return newSystemErrorWithCausef(err, "running prestart hook %d", i) } } } // Sync with child. - if err := utils.WriteJSON(p.parentPipe, syncT{procResume}); err != nil { - return newSystemError(err) + if err := writeSync(p.parentPipe, procResume); err != nil { + return newSystemErrorWithCause(err, "writing syncT 'resume'") } sentResume = true - case procError: - // wait for the child process to fully complete and receive an error message - // if one was encoutered - if err := dec.Decode(&ierr); err != nil && err != io.EOF { - return newSystemError(err) - } - if ierr != nil { - break loop - } - // Programmer error. - panic("No error following JSON procError payload.") default: - return newSystemError(fmt.Errorf("invalid JSON synchronisation payload from child")) + return newSystemError(fmt.Errorf("invalid JSON payload from child")) } - } + + return nil + }) + if !sentRun { - return newSystemError(fmt.Errorf("could not synchronise with container process")) + return newSystemErrorWithCause(ierr, "container init") } if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process")) } - if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil { - return newSystemError(err) + if err := unix.Shutdown(int(p.parentPipe.Fd()), unix.SHUT_WR); err != nil { + return newSystemErrorWithCause(err, "shutting down init pipe") } + // Must be done after Shutdown so the child will exit and we can wait for it. if ierr != nil { p.wait() - return newSystemError(ierr) + return ierr } return nil } @@ -363,7 +445,7 @@ func (p *initProcess) wait() (*os.ProcessState, error) { } // we should kill all processes in cgroup when init is died if we use host PID namespace if p.sharePidns { - killCgroupProcesses(p.manager) + signalAllProcesses(p.manager, unix.SIGKILL) } return p.cmd.ProcessState, nil } @@ -379,8 +461,9 @@ func (p *initProcess) terminate() error { return err } -func (p *initProcess) startTime() (string, error) { - return system.GetProcessStartTime(p.pid()) +func (p *initProcess) startTime() (uint64, error) { + stat, err := system.Stat(p.pid()) + return stat.StartTime, err } func (p *initProcess) sendConfig() error { @@ -412,7 +495,7 @@ func (p *initProcess) signal(sig os.Signal) error { if !ok { return errors.New("os: unsupported signal type") } - return syscall.Kill(p.pid(), s) + return unix.Kill(p.pid(), s) } func (p *initProcess) setExternalDescriptors(newFds []string) { @@ -424,9 +507,17 @@ func getPipeFds(pid int) ([]string, error) { dirPath := filepath.Join("/proc", strconv.Itoa(pid), "/fd") for i := 0; i < 3; i++ { + // XXX: This breaks if the path is not a valid symlink (which can + // happen in certain particularly unlucky mount namespace setups). f := filepath.Join(dirPath, strconv.Itoa(i)) target, err := os.Readlink(f) if err != nil { + // Ignore permission errors, for rootless containers and other + // non-dumpable processes. if we can't get the fd for a particular + // file, there's not much we can do. + if os.IsPermission(err) { + continue + } return fds, err } fds[i] = target @@ -434,16 +525,18 @@ func getPipeFds(pid int) ([]string, error) { return fds, nil } -// InitializeIO creates pipes for use with the process's STDIO -// and returns the opposite side for each -func (p *Process) InitializeIO(rootuid int) (i *IO, err error) { +// InitializeIO creates pipes for use with the process's stdio and returns the +// opposite side for each. Do not use this if you want to have a pseudoterminal +// set up for you by libcontainer (TODO: fix that too). +// TODO: This is mostly unnecessary, and should be handled by clients. +func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) { var fds []uintptr i = &IO{} // cleanup in case of an error defer func() { if err != nil { for _, fd := range fds { - syscall.Close(int(fd)) + unix.Close(int(fd)) } } }() @@ -466,9 +559,9 @@ func (p *Process) InitializeIO(rootuid int) (i *IO, err error) { } fds = append(fds, r.Fd(), w.Fd()) p.Stderr, i.Stderr = w, r - // change ownership of the pipes incase we are in a user namespace + // change ownership of the pipes in case we are in a user namespace for _, fd := range fds { - if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil { + if err := unix.Fchown(int(fd), rootuid, rootgid); err != nil { return nil, err } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go index a96f4ca5f5a428416e64ee9985b06d7326eb3277..408916ad936ce2ea6571b1f55bea421438035137 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go @@ -17,20 +17,20 @@ func newRestoredProcess(pid int, fds []string) (*restoredProcess, error) { if err != nil { return nil, err } - started, err := system.GetProcessStartTime(pid) + stat, err := system.Stat(pid) if err != nil { return nil, err } return &restoredProcess{ proc: proc, - processStartTime: started, + processStartTime: stat.StartTime, fds: fds, }, nil } type restoredProcess struct { proc *os.Process - processStartTime string + processStartTime uint64 fds []string } @@ -60,7 +60,7 @@ func (p *restoredProcess) wait() (*os.ProcessState, error) { return st, nil } -func (p *restoredProcess) startTime() (string, error) { +func (p *restoredProcess) startTime() (uint64, error) { return p.processStartTime, nil } @@ -81,7 +81,7 @@ func (p *restoredProcess) setExternalDescriptors(newFds []string) { // a persisted state. type nonChildProcess struct { processPid int - processStartTime string + processStartTime uint64 fds []string } @@ -101,7 +101,7 @@ func (p *nonChildProcess) wait() (*os.ProcessState, error) { return nil, newGenericError(fmt.Errorf("restored process cannot be waited on"), SystemError) } -func (p *nonChildProcess) startTime() (string, error) { +func (p *nonChildProcess) startTime() (uint64, error) { return p.processStartTime, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index 1a880fe9ee4b23f88570408f6c02d28cad89a126..6bd6da74acef667eb41c68c529304e80522e6196 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -11,112 +11,178 @@ import ( "path" "path/filepath" "strings" - "syscall" "time" - "github.com/docker/docker/pkg/mount" - "github.com/docker/docker/pkg/symlink" + "github.com/cyphar/filepath-securejoin" + "github.com/mrunalp/fileutils" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/label" + "github.com/opencontainers/runc/libcontainer/mount" "github.com/opencontainers/runc/libcontainer/system" libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/selinux/go-selinux/label" + + "golang.org/x/sys/unix" ) -const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV +const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV -// setupRootfs sets up the devices, mount points, and filesystems for use inside a -// new mount namespace. -func setupRootfs(config *configs.Config, console *linuxConsole, pipe io.ReadWriter) (err error) { +// needsSetupDev returns true if /dev needs to be set up. +func needsSetupDev(config *configs.Config) bool { + for _, m := range config.Mounts { + if m.Device == "bind" && libcontainerUtils.CleanPath(m.Destination) == "/dev" { + return false + } + } + return true +} + +// prepareRootfs sets up the devices, mount points, and filesystems for use +// inside a new mount namespace. It doesn't set anything as ro. You must call +// finalizeRootfs after this function to finish setting up the rootfs. +func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { + config := iConfig.Config if err := prepareRoot(config); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "preparing rootfs") } - setupDev := len(config.Devices) != 0 + hasCgroupns := config.Namespaces.Contains(configs.NEWCGROUP) + setupDev := needsSetupDev(config) for _, m := range config.Mounts { for _, precmd := range m.PremountCmds { if err := mountCmd(precmd); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "running premount command") } } - if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil { - return newSystemError(err) + if err := mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns); err != nil { + return newSystemErrorWithCausef(err, "mounting %q to rootfs %q at %q", m.Source, config.Rootfs, m.Destination) } for _, postcmd := range m.PostmountCmds { if err := mountCmd(postcmd); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "running postmount command") } } } + if setupDev { if err := createDevices(config); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "creating device nodes") } - if err := setupPtmx(config, console); err != nil { - return newSystemError(err) + if err := setupPtmx(config); err != nil { + return newSystemErrorWithCause(err, "setting up ptmx") } if err := setupDevSymlinks(config.Rootfs); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "setting up /dev symlinks") } } + // Signal the parent to run the pre-start hooks. // The hooks are run after the mounts are setup, but before we switch to the new // root, so that the old root is still available in the hooks for any mount // manipulations. + // Note that iConfig.Cwd is not guaranteed to exist here. if err := syncParentHooks(pipe); err != nil { return err } - if err := syscall.Chdir(config.Rootfs); err != nil { - return newSystemError(err) + + // The reason these operations are done here rather than in finalizeRootfs + // is because the console-handling code gets quite sticky if we have to set + // up the console before doing the pivot_root(2). This is because the + // Console API has to also work with the ExecIn case, which means that the + // API must be able to deal with being inside as well as outside the + // container. It's just cleaner to do this here (at the expense of the + // operation not being perfectly split). + + if err := unix.Chdir(config.Rootfs); err != nil { + return newSystemErrorWithCausef(err, "changing dir to %q", config.Rootfs) } + if config.NoPivotRoot { err = msMoveRoot(config.Rootfs) + } else if config.Namespaces.Contains(configs.NEWNS) { + err = pivotRoot(config.Rootfs) } else { - err = pivotRoot(config.Rootfs, config.PivotDir) + err = chroot(config.Rootfs) } if err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "jailing process inside rootfs") } + if setupDev { if err := reOpenDevNull(); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "reopening /dev/null inside container") } } - // remount dev as ro if specifed + + if cwd := iConfig.Cwd; cwd != "" { + // Note that spec.Process.Cwd can contain unclean value like "../../../../foo/bar...". + // However, we are safe to call MkDirAll directly because we are in the jail here. + if err := os.MkdirAll(cwd, 0755); err != nil { + return err + } + } + + return nil +} + +// finalizeRootfs sets anything to ro if necessary. You must call +// prepareRootfs first. +func finalizeRootfs(config *configs.Config) (err error) { + // remount dev as ro if specified for _, m := range config.Mounts { - if m.Destination == "/dev" { - if m.Flags&syscall.MS_RDONLY != 0 { - if err := remountReadonly(m.Destination); err != nil { - return newSystemError(err) + if libcontainerUtils.CleanPath(m.Destination) == "/dev" { + if m.Flags&unix.MS_RDONLY == unix.MS_RDONLY { + if err := remountReadonly(m); err != nil { + return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination) } } break } } + // set rootfs ( / ) as readonly if config.Readonlyfs { if err := setReadonly(); err != nil { - return newSystemError(err) + return newSystemErrorWithCause(err, "setting rootfs as readonly") } } - syscall.Umask(0022) + + unix.Umask(0022) return nil } -func mountCmd(cmd configs.Command) error { +// /tmp has to be mounted as private to allow MS_MOVE to work in all situations +func prepareTmp(topTmpDir string) (string, error) { + tmpdir, err := ioutil.TempDir(topTmpDir, "runctop") + if err != nil { + return "", err + } + if err := unix.Mount(tmpdir, tmpdir, "bind", unix.MS_BIND, ""); err != nil { + return "", err + } + if err := unix.Mount("", tmpdir, "", uintptr(unix.MS_PRIVATE), ""); err != nil { + return "", err + } + return tmpdir, nil +} + +func cleanupTmp(tmpdir string) error { + unix.Unmount(tmpdir, 0) + return os.RemoveAll(tmpdir) +} +func mountCmd(cmd configs.Command) error { command := exec.Command(cmd.Path, cmd.Args[:]...) command.Env = cmd.Env command.Dir = cmd.Dir if out, err := command.CombinedOutput(); err != nil { return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err) } - return nil } -func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { +func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { var ( dest = m.Destination ) @@ -140,18 +206,50 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { if err := mountPropagate(m, rootfs, ""); err != nil { return err } + return label.SetFileLabel(dest, mountLabel) } - return label.SetFileLabel(dest, mountLabel) + return nil case "tmpfs": + copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP + tmpDir := "" stat, err := os.Stat(dest) if err != nil { if err := os.MkdirAll(dest, 0755); err != nil { return err } } + if copyUp { + tmpdir, err := prepareTmp("/tmp") + if err != nil { + return newSystemErrorWithCause(err, "tmpcopyup: failed to setup tmpdir") + } + defer cleanupTmp(tmpdir) + tmpDir, err = ioutil.TempDir(tmpdir, "runctmpdir") + if err != nil { + return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") + } + defer os.RemoveAll(tmpDir) + m.Destination = tmpDir + } if err := mountPropagate(m, rootfs, mountLabel); err != nil { return err } + if copyUp { + if err := fileutils.CopyDirectory(dest, tmpDir); err != nil { + errMsg := fmt.Errorf("tmpcopyup: failed to copy %s to %s: %v", dest, tmpDir, err) + if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { + return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) + } + return errMsg + } + if err := unix.Mount(tmpDir, dest, "", unix.MS_MOVE, ""); err != nil { + errMsg := fmt.Errorf("tmpcopyup: failed to move mount %s to %s: %v", tmpDir, dest, err) + if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { + return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) + } + return errMsg + } + } if stat != nil { if err = os.Chmod(dest, stat.Mode()); err != nil { return err @@ -169,7 +267,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { // any previous mounts can invalidate the next mount's destination. // this can happen when a user specifies mounts within other mounts to cause breakouts or other // evil stuff to try to escape the container's rootfs. - if dest, err = symlink.FollowSymlinkInScope(filepath.Join(rootfs, m.Destination), rootfs); err != nil { + if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { return err } if err := checkMountDestination(rootfs, dest); err != nil { @@ -185,7 +283,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } // bind mount won't change mount options, we need remount to make mount options effective. // first check that we have non-default options required before attempting a remount - if m.Flags&^(syscall.MS_REC|syscall.MS_REMOUNT|syscall.MS_BIND) != 0 { + if m.Flags&^(unix.MS_REC|unix.MS_REMOUNT|unix.MS_BIND) != 0 { // only remount if unique mount options are set if err := remount(m, rootfs); err != nil { return err @@ -221,48 +319,71 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { Data: "mode=755", PropagationFlags: m.PropagationFlags, } - if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil { + if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil { return err } for _, b := range binds { - if err := mountToRootfs(b, rootfs, mountLabel); err != nil { - return err + if enableCgroupns { + subsystemPath := filepath.Join(rootfs, b.Destination) + if err := os.MkdirAll(subsystemPath, 0755); err != nil { + return err + } + flags := defaultMountFlags + if m.Flags&unix.MS_RDONLY != 0 { + flags = flags | unix.MS_RDONLY + } + cgroupmount := &configs.Mount{ + Source: "cgroup", + Device: "cgroup", + Destination: subsystemPath, + Flags: flags, + Data: filepath.Base(subsystemPath), + } + if err := mountNewCgroup(cgroupmount); err != nil { + return err + } + } else { + if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil { + return err + } } } - // create symlinks for merged cgroups - cwd, err := os.Getwd() - if err != nil { - return err - } - if err := os.Chdir(filepath.Join(rootfs, m.Destination)); err != nil { - return err - } for _, mc := range merged { for _, ss := range strings.Split(mc, ",") { - if err := os.Symlink(mc, ss); err != nil { - // if cgroup already exists, then okay(it could have been created before) - if os.IsExist(err) { - continue - } - os.Chdir(cwd) + // symlink(2) is very dumb, it will just shove the path into + // the link and doesn't do any checks or relative path + // conversion. Also, don't error out if the cgroup already exists. + if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) { return err } } } - if err := os.Chdir(cwd); err != nil { - return err - } - if m.Flags&syscall.MS_RDONLY != 0 { + if m.Flags&unix.MS_RDONLY != 0 { // remount cgroup root as readonly mcgrouproot := &configs.Mount{ + Source: m.Destination, + Device: "bind", Destination: m.Destination, - Flags: defaultMountFlags | syscall.MS_RDONLY, + Flags: defaultMountFlags | unix.MS_RDONLY | unix.MS_BIND, } if err := remount(mcgrouproot, rootfs); err != nil { return err } } default: + // ensure that the destination of the mount is resolved of symlinks at mount time because + // any previous mounts can invalidate the next mount's destination. + // this can happen when a user specifies mounts within other mounts to cause breakouts or other + // evil stuff to try to escape the container's rootfs. + var err error + if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { + return err + } + if err := checkMountDestination(rootfs, dest); err != nil { + return err + } + // update the mount with the correct dest after symlinks are resolved. + m.Destination = dest if err := os.MkdirAll(dest, 0755); err != nil { return err } @@ -272,7 +393,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { - mounts, err := cgroups.GetCgroupMounts() + mounts, err := cgroups.GetCgroupMounts(false) if err != nil { return nil, err } @@ -285,7 +406,7 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { var binds []*configs.Mount for _, mm := range mounts { - dir, err := mm.GetThisCgroupDir(cgroupPaths) + dir, err := mm.GetOwnCgroup(cgroupPaths) if err != nil { return nil, err } @@ -296,8 +417,8 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { binds = append(binds, &configs.Mount{ Device: "bind", Source: filepath.Join(mm.Mountpoint, relDir), - Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")), - Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags, + Destination: filepath.Join(m.Destination, filepath.Base(mm.Mountpoint)), + Flags: unix.MS_BIND | unix.MS_REC | m.Flags, PropagationFlags: m.PropagationFlags, }) } @@ -308,9 +429,6 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { // checkMountDestination checks to ensure that the mount destination is not over the top of /proc. // dest is required to be an abs path and have any symlinks resolved before calling this function. func checkMountDestination(rootfs, dest string) error { - if libcontainerUtils.CleanPath(rootfs) == libcontainerUtils.CleanPath(dest) { - return fmt.Errorf("mounting into / is prohibited") - } invalidDestinations := []string{ "/proc", } @@ -322,6 +440,9 @@ func checkMountDestination(rootfs, dest string) error { "/proc/diskstats", "/proc/meminfo", "/proc/stat", + "/proc/swaps", + "/proc/uptime", + "/proc/loadavg", "/proc/net/dev", } for _, valid := range validDestinations { @@ -338,7 +459,7 @@ func checkMountDestination(rootfs, dest string) error { if err != nil { return err } - if path == "." || !strings.HasPrefix(path, "..") { + if path != "." && !strings.HasPrefix(path, "..") { return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid) } } @@ -374,22 +495,22 @@ func setupDevSymlinks(rootfs string) error { // needs to be called after we chroot/pivot into the container's rootfs so that any // symlinks are resolved locally. func reOpenDevNull() error { - var stat, devNullStat syscall.Stat_t + var stat, devNullStat unix.Stat_t file, err := os.OpenFile("/dev/null", os.O_RDWR, 0) if err != nil { return fmt.Errorf("Failed to open /dev/null - %s", err) } defer file.Close() - if err := syscall.Fstat(int(file.Fd()), &devNullStat); err != nil { + if err := unix.Fstat(int(file.Fd()), &devNullStat); err != nil { return err } for fd := 0; fd < 3; fd++ { - if err := syscall.Fstat(fd, &stat); err != nil { + if err := unix.Fstat(fd, &stat); err != nil { return err } if stat.Rdev == devNullStat.Rdev { // Close and re-open the fd. - if err := syscall.Dup3(int(file.Fd()), fd, 0); err != nil { + if err := unix.Dup3(int(file.Fd()), fd, 0); err != nil { return err } } @@ -400,16 +521,16 @@ func reOpenDevNull() error { // Create the device nodes in the container. func createDevices(config *configs.Config) error { useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER) - oldMask := syscall.Umask(0000) + oldMask := unix.Umask(0000) for _, node := range config.Devices { // containers running in a user namespace are not allowed to mknod // devices so we can just bind mount it from the host. if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil { - syscall.Umask(oldMask) + unix.Umask(oldMask) return err } } - syscall.Umask(oldMask) + unix.Umask(oldMask) return nil } @@ -421,7 +542,7 @@ func bindMountDeviceNode(dest string, node *configs.Device) error { if f != nil { f.Close() } - return syscall.Mount(node.Path, dest, "bind", syscall.MS_BIND, "") + return unix.Mount(node.Path, dest, "bind", unix.MS_BIND, "") } // Creates the device node in the rootfs of the container. @@ -448,17 +569,19 @@ func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { func mknodDevice(dest string, node *configs.Device) error { fileMode := node.FileMode switch node.Type { - case 'c': - fileMode |= syscall.S_IFCHR + case 'c', 'u': + fileMode |= unix.S_IFCHR case 'b': - fileMode |= syscall.S_IFBLK + fileMode |= unix.S_IFBLK + case 'p': + fileMode |= unix.S_IFIFO default: return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path) } - if err := syscall.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil { + if err := unix.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil { return err } - return syscall.Chown(dest, int(node.Uid), int(node.Gid)) + return unix.Chown(dest, int(node.Uid), int(node.Gid)) } func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info { @@ -504,10 +627,10 @@ func getParentMount(rootfs string) (string, string, error) { } // Make parent mount private if it was shared -func rootfsParentMountPrivate(config *configs.Config) error { +func rootfsParentMountPrivate(rootfs string) error { sharedMount := false - parentMount, optionalOpts, err := getParentMount(config.Rootfs) + parentMount, optionalOpts, err := getParentMount(rootfs) if err != nil { return err } @@ -525,33 +648,36 @@ func rootfsParentMountPrivate(config *configs.Config) error { // shared. Secondly when we bind mount rootfs it will propagate to // parent namespace and we don't want that to happen. if sharedMount { - return syscall.Mount("", parentMount, "", syscall.MS_PRIVATE, "") + return unix.Mount("", parentMount, "", unix.MS_PRIVATE, "") } return nil } func prepareRoot(config *configs.Config) error { - flag := syscall.MS_SLAVE | syscall.MS_REC + flag := unix.MS_SLAVE | unix.MS_REC if config.RootPropagation != 0 { flag = config.RootPropagation } - if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil { + if err := unix.Mount("", "/", "", uintptr(flag), ""); err != nil { return err } - if err := rootfsParentMountPrivate(config); err != nil { + // Make parent mount private to make sure following bind mount does + // not propagate in other namespaces. Also it will help with kernel + // check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent)) + if err := rootfsParentMountPrivate(config.Rootfs); err != nil { return err } - return syscall.Mount(config.Rootfs, config.Rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, "") + return unix.Mount(config.Rootfs, config.Rootfs, "bind", unix.MS_BIND|unix.MS_REC, "") } func setReadonly() error { - return syscall.Mount("/", "/", "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "") + return unix.Mount("/", "/", "bind", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY|unix.MS_REC, "") } -func setupPtmx(config *configs.Config, console *linuxConsole) error { +func setupPtmx(config *configs.Config) error { ptmx := filepath.Join(config.Rootfs, "dev/ptmx") if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) { return err @@ -559,59 +685,115 @@ func setupPtmx(config *configs.Config, console *linuxConsole) error { if err := os.Symlink("pts/ptmx", ptmx); err != nil { return fmt.Errorf("symlink dev ptmx %s", err) } - if console != nil { - return console.mount(config.Rootfs, config.MountLabel) - } return nil } -func pivotRoot(rootfs, pivotBaseDir string) (err error) { - if pivotBaseDir == "" { - pivotBaseDir = "/" - } - tmpDir := filepath.Join(rootfs, pivotBaseDir) - if err := os.MkdirAll(tmpDir, 0755); err != nil { - return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err) +// pivotRoot will call pivot_root such that rootfs becomes the new root +// filesystem, and everything else is cleaned up. +func pivotRoot(rootfs string) error { + // While the documentation may claim otherwise, pivot_root(".", ".") is + // actually valid. What this results in is / being the new root but + // /proc/self/cwd being the old root. Since we can play around with the cwd + // with pivot_root this allows us to pivot without creating directories in + // the rootfs. Shout-outs to the LXC developers for giving us this idea. + + oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err != nil { + return err } - pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root") + defer unix.Close(oldroot) + + newroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err) + return err } - defer func() { - errVal := os.Remove(pivotDir) - if err == nil { - err = errVal - } - }() - if err := syscall.PivotRoot(rootfs, pivotDir); err != nil { + defer unix.Close(newroot) + + // Change to the new root so that the pivot_root actually acts on it. + if err := unix.Fchdir(newroot); err != nil { + return err + } + + if err := unix.PivotRoot(".", "."); err != nil { return fmt.Errorf("pivot_root %s", err) } - if err := syscall.Chdir("/"); err != nil { - return fmt.Errorf("chdir / %s", err) + + // Currently our "." is oldroot (according to the current kernel code). + // However, purely for safety, we will fchdir(oldroot) since there isn't + // really any guarantee from the kernel what /proc/self/cwd will be after a + // pivot_root(2). + + if err := unix.Fchdir(oldroot); err != nil { + return err } - // path to pivot dir now changed, update - pivotDir = filepath.Join(pivotBaseDir, filepath.Base(pivotDir)) - // Make pivotDir rprivate to make sure any of the unmounts don't - // propagate to parent. - if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil { + // Make oldroot rslave to make sure our unmounts don't propagate to the + // host (and thus bork the machine). We don't use rprivate because this is + // known to cause issues due to races where we still have a reference to a + // mount while a process in the host namespace are trying to operate on + // something they think has no mounts (devicemapper in particular). + if err := unix.Mount("", ".", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + return err + } + // Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd. + if err := unix.Unmount(".", unix.MNT_DETACH); err != nil { return err } - if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { - return fmt.Errorf("unmount pivot_root dir %s", err) + // Switch back to our shiny new root. + if err := unix.Chdir("/"); err != nil { + return fmt.Errorf("chdir / %s", err) } return nil } func msMoveRoot(rootfs string) error { - if err := syscall.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil { + mountinfos, err := mount.GetMounts() + if err != nil { return err } - if err := syscall.Chroot("."); err != nil { + + absRootfs, err := filepath.Abs(rootfs) + if err != nil { return err } - return syscall.Chdir("/") + + for _, info := range mountinfos { + p, err := filepath.Abs(info.Mountpoint) + if err != nil { + return err + } + // Umount every syfs and proc file systems, except those under the container rootfs + if (info.Fstype != "proc" && info.Fstype != "sysfs") || filepath.HasPrefix(p, absRootfs) { + continue + } + // Be sure umount events are not propagated to the host. + if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + return err + } + if err := unix.Unmount(p, unix.MNT_DETACH); err != nil { + if err != unix.EINVAL && err != unix.EPERM { + return err + } else { + // If we have not privileges for umounting (e.g. rootless), then + // cover the path. + if err := unix.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil { + return err + } + } + } + } + if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil { + return err + } + return chroot(rootfs) +} + +func chroot(rootfs string) error { + if err := unix.Chroot("."); err != nil { + return err + } + return unix.Chdir("/") } // createIfNotExists creates a file or a directory only if it does not already exist. @@ -634,18 +816,34 @@ func createIfNotExists(path string, isDir bool) error { return nil } -// remountReadonly will bind over the top of an existing path and ensure that it is read-only. -func remountReadonly(path string) error { +// readonlyPath will make a path read only. +func readonlyPath(path string) error { + if err := unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + return unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY|unix.MS_REC, "") +} + +// remountReadonly will remount an existing mount point and ensure that it is read-only. +func remountReadonly(m *configs.Mount) error { + var ( + dest = m.Destination + flags = m.Flags + ) for i := 0; i < 5; i++ { - if err := syscall.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) { + // There is a special case in the kernel for + // MS_REMOUNT | MS_BIND, which allows us to change only the + // flags even as an unprivileged user (i.e. user namespace) + // assuming we don't drop any security related flags (nodev, + // nosuid, etc.). So, let's use that case so that we can do + // this re-mount without failing in a userns. + flags |= unix.MS_REMOUNT | unix.MS_BIND | unix.MS_RDONLY + if err := unix.Mount("", dest, "", uintptr(flags), ""); err != nil { switch err { - case syscall.EINVAL: - // Probably not a mountpoint, use bind-mount - if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil { - return err - } - return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "") - case syscall.EBUSY: + case unix.EBUSY: time.Sleep(100 * time.Millisecond) continue default: @@ -654,13 +852,19 @@ func remountReadonly(path string) error { } return nil } - return fmt.Errorf("unable to mount %s as readonly max retries reached", path) + return fmt.Errorf("unable to mount %s as readonly max retries reached", dest) } -// maskFile bind mounts /dev/null over the top of the specified path inside a container -// to avoid security issues from processes reading information from non-namespace aware mounts ( proc/kcore ). -func maskFile(path string) error { - if err := syscall.Mount("/dev/null", path, "", syscall.MS_BIND, ""); err != nil && !os.IsNotExist(err) { +// maskPath masks the top of the specified path inside a container to avoid +// security issues from processes reading information from non-namespace aware +// mounts ( proc/kcore ). +// For files, maskPath bind mounts /dev/null over the top of the specified path. +// For directories, maskPath mounts read-only tmpfs over the top of the specified path. +func maskPath(path string, mountLabel string) error { + if err := unix.Mount("/dev/null", path, "", unix.MS_BIND, ""); err != nil && !os.IsNotExist(err) { + if err == unix.ENOTDIR { + return unix.Mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("", mountLabel)) + } return err } return nil @@ -680,10 +884,7 @@ func remount(m *configs.Mount, rootfs string) error { if !strings.HasPrefix(dest, rootfs) { dest = filepath.Join(rootfs, dest) } - if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil { - return err - } - return nil + return unix.Mount(m.Source, dest, m.Device, uintptr(m.Flags|unix.MS_REMOUNT), "") } // Do the mount operation followed by additional mounts required to take care @@ -694,21 +895,38 @@ func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { data = label.FormatMountLabel(m.Data, mountLabel) flags = m.Flags ) - if dest == "/dev" { - flags &= ^syscall.MS_RDONLY + if libcontainerUtils.CleanPath(dest) == "/dev" { + flags &= ^unix.MS_RDONLY } - if !strings.HasPrefix(dest, rootfs) { + + copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP + if !(copyUp || strings.HasPrefix(dest, rootfs)) { dest = filepath.Join(rootfs, dest) } - if err := syscall.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { + if err := unix.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { return err } for _, pflag := range m.PropagationFlags { - if err := syscall.Mount("", dest, "", uintptr(pflag), ""); err != nil { + if err := unix.Mount("", dest, "", uintptr(pflag), ""); err != nil { return err } } return nil } + +func mountNewCgroup(m *configs.Mount) error { + var ( + data = m.Data + source = m.Source + ) + if data == "systemd" { + data = cgroups.CgroupNamePrefix + data + source = "systemd" + } + if err := unix.Mount(source, m.Destination, m.Device, uintptr(m.Flags), data); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go index a3bb07708b93a6a7666cf008a0e4e3f62eb59038..d755984bc0f9eb0995f251a007eef32f42ecd59e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux_test.go @@ -2,16 +2,28 @@ package libcontainer -import "testing" +import ( + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" +) func TestCheckMountDestOnProc(t *testing.T) { - dest := "/rootfs/proc/" + dest := "/rootfs/proc/sys" err := checkMountDestination("/rootfs", dest) if err == nil { t.Fatal("destination inside proc should return an error") } } +func TestCheckMountDestOnProcChroot(t *testing.T) { + dest := "/rootfs/proc/" + err := checkMountDestination("/rootfs", dest) + if err != nil { + t.Fatal("destination inside proc when using chroot should not return an error") + } +} + func TestCheckMountDestInSys(t *testing.T) { dest := "/rootfs//sys/fs/cgroup" err := checkMountDestination("/rootfs", dest) @@ -28,10 +40,62 @@ func TestCheckMountDestFalsePositive(t *testing.T) { } } -func TestCheckMountRoot(t *testing.T) { - dest := "/rootfs" - err := checkMountDestination("/rootfs", dest) - if err == nil { - t.Fatal(err) +func TestNeedsSetupDev(t *testing.T) { + config := &configs.Config{ + Mounts: []*configs.Mount{ + { + Device: "bind", + Source: "/dev", + Destination: "/dev", + }, + }, + } + if needsSetupDev(config) { + t.Fatal("expected needsSetupDev to be false, got true") + } +} + +func TestNeedsSetupDevStrangeSource(t *testing.T) { + config := &configs.Config{ + Mounts: []*configs.Mount{ + { + Device: "bind", + Source: "/devx", + Destination: "/dev", + }, + }, + } + if needsSetupDev(config) { + t.Fatal("expected needsSetupDev to be false, got true") + } +} + +func TestNeedsSetupDevStrangeDest(t *testing.T) { + config := &configs.Config{ + Mounts: []*configs.Mount{ + { + Device: "bind", + Source: "/dev", + Destination: "/devx", + }, + }, + } + if !needsSetupDev(config) { + t.Fatal("expected needsSetupDev to be true, got false") + } +} + +func TestNeedsSetupDevStrangeSourceDest(t *testing.T) { + config := &configs.Config{ + Mounts: []*configs.Mount{ + { + Device: "bind", + Source: "/devx", + Destination: "/devx", + }, + }, + } + if !needsSetupDev(config) { + t.Fatal("expected needsSetupDev to be true, got false") } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go index 3b9a7595f2bf07fb303ef20adb795277845f1fa1..ded5a6bbc8bba9e0291b26d4402839a2daea1680 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go @@ -36,6 +36,11 @@ var archs = map[string]string{ "SCMP_ARCH_MIPSEL": "mipsel", "SCMP_ARCH_MIPSEL64": "mipsel64", "SCMP_ARCH_MIPSEL64N32": "mipsel64n32", + "SCMP_ARCH_PPC": "ppc", + "SCMP_ARCH_PPC64": "ppc64", + "SCMP_ARCH_PPC64LE": "ppc64le", + "SCMP_ARCH_S390": "s390", + "SCMP_ARCH_S390X": "s390x", } // ConvertStringToOperator converts a string into a Seccomp comparison operator. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go index 623e227748d849bc6d015ffeecfc574425105f76..d99f3fe640c6ddd28aa4e835c8cc0586b9189a56 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go @@ -5,24 +5,26 @@ package seccomp import ( "bufio" "fmt" - "log" "os" "strings" - "syscall" "github.com/opencontainers/runc/libcontainer/configs" libseccomp "github.com/seccomp/libseccomp-golang" + + "golang.org/x/sys/unix" ) var ( actAllow = libseccomp.ActAllow actTrap = libseccomp.ActTrap actKill = libseccomp.ActKill - actTrace = libseccomp.ActTrace.SetReturnCode(int16(syscall.EPERM)) - actErrno = libseccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)) + actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)) + actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)) +) - // SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER. - SeccompModeFilter = uintptr(2) +const ( + // Linux system calls can have at most 6 arguments + syscallMaxArguments int = 6 ) // Filters given syscalls in a container, preventing them from being used @@ -48,11 +50,11 @@ func InitSeccomp(config *configs.Seccomp) error { for _, arch := range config.Architectures { scmpArch, err := libseccomp.GetArchFromString(arch) if err != nil { - return err + return fmt.Errorf("error validating Seccomp architecture: %s", err) } if err := filter.AddArch(scmpArch); err != nil { - return err + return fmt.Errorf("error adding architecture to seccomp filter: %s", err) } } @@ -85,9 +87,9 @@ func IsEnabled() bool { s, err := parseStatusFile("/proc/self/status") if err != nil { // Check if Seccomp is supported, via CONFIG_SECCOMP. - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL { + if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { // Make sure the kernel has CONFIG_SECCOMP_FILTER. - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL { + if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { return true } } @@ -167,36 +169,61 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error { // Ignore it, don't error out callNum, err := libseccomp.GetSyscallFromName(call.Name) if err != nil { - log.Printf("Error resolving syscall name %s: %s - ignoring syscall.", call.Name, err) return nil } // Convert the call's action to the libseccomp equivalent callAct, err := getAction(call.Action) if err != nil { - return err + return fmt.Errorf("action in seccomp profile is invalid: %s", err) } // Unconditional match - just add the rule if len(call.Args) == 0 { if err = filter.AddRule(callNum, callAct); err != nil { - return err + return fmt.Errorf("error adding seccomp filter rule for syscall %s: %s", call.Name, err) } } else { - // Conditional match - convert the per-arg rules into library format + // If two or more arguments have the same condition, + // Revert to old behavior, adding each condition as a separate rule + argCounts := make([]uint, syscallMaxArguments) conditions := []libseccomp.ScmpCondition{} for _, cond := range call.Args { newCond, err := getCondition(cond) if err != nil { - return err + return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %s", call.Name, err) } + argCounts[cond.Index] += 1 + conditions = append(conditions, newCond) } - if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil { - return err + hasMultipleArgs := false + for _, count := range argCounts { + if count > 1 { + hasMultipleArgs = true + break + } + } + + if hasMultipleArgs { + // Revert to old behavior + // Add each condition attached to a separate rule + for _, cond := range conditions { + condArr := []libseccomp.ScmpCondition{cond} + + if err = filter.AddRuleConditional(callNum, callAct, condArr); err != nil { + return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err) + } + } + } else { + // No conditions share same argument + // Use new, proper behavior + if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil { + return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err) + } } } @@ -214,10 +241,6 @@ func parseStatusFile(path string) (map[string]string, error) { status := make(map[string]string) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - text := s.Text() parts := strings.Split(text, ":") @@ -227,5 +250,9 @@ func parseStatusFile(path string) (map[string]string, error) { status[parts[0]] = parts[1] } + if err := s.Err(); err != nil { + return nil, err + } + return status, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go index 888483e7687f7f18ba18c30f7da1aead621e5e97..44df1ad4c269a80447e2ffee69fed29803b55d84 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go @@ -10,7 +10,7 @@ import ( var ErrSeccompNotEnabled = errors.New("seccomp: config provided but seccomp not supported") -// Seccomp not supported, do nothing +// InitSeccomp does nothing because seccomp is not supported. func InitSeccomp(config *configs.Seccomp) error { if config != nil { return ErrSeccompNotEnabled diff --git a/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux.go b/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux.go deleted file mode 100644 index 3bdce10ca3c787d321d697f2b26821fe65b07c8e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux.go +++ /dev/null @@ -1,479 +0,0 @@ -// +build linux - -package selinux - -import ( - "bufio" - "crypto/rand" - "encoding/binary" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "syscall" - - "github.com/docker/docker/pkg/mount" - "github.com/opencontainers/runc/libcontainer/system" -) - -const ( - Enforcing = 1 - Permissive = 0 - Disabled = -1 - selinuxDir = "/etc/selinux/" - selinuxConfig = selinuxDir + "config" - selinuxTypeTag = "SELINUXTYPE" - selinuxTag = "SELINUX" - selinuxPath = "/sys/fs/selinux" - xattrNameSelinux = "security.selinux" - stRdOnly = 0x01 -) - -var ( - assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) - mcsList = make(map[string]bool) - selinuxfs = "unknown" - selinuxEnabled = false // Stores whether selinux is currently enabled - selinuxEnabledChecked = false // Stores whether selinux enablement has been checked or established yet -) - -type SELinuxContext map[string]string - -// SetDisabled disables selinux support for the package -func SetDisabled() { - selinuxEnabled, selinuxEnabledChecked = false, true -} - -// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs -// filesystem or an empty string if no mountpoint is found. Selinuxfs is -// a proc-like pseudo-filesystem that exposes the selinux policy API to -// processes. The existence of an selinuxfs mount is used to determine -// whether selinux is currently enabled or not. -func getSelinuxMountPoint() string { - if selinuxfs != "unknown" { - return selinuxfs - } - selinuxfs = "" - - mounts, err := mount.GetMounts() - if err != nil { - return selinuxfs - } - for _, mount := range mounts { - if mount.Fstype == "selinuxfs" { - selinuxfs = mount.Mountpoint - break - } - } - if selinuxfs != "" { - var buf syscall.Statfs_t - syscall.Statfs(selinuxfs, &buf) - if (buf.Flags & stRdOnly) == 1 { - selinuxfs = "" - } - } - return selinuxfs -} - -// SelinuxEnabled returns whether selinux is currently enabled. -func SelinuxEnabled() bool { - if selinuxEnabledChecked { - return selinuxEnabled - } - selinuxEnabledChecked = true - if fs := getSelinuxMountPoint(); fs != "" { - if con, _ := Getcon(); con != "kernel" { - selinuxEnabled = true - } - } - return selinuxEnabled -} - -func readConfig(target string) (value string) { - var ( - val, key string - bufin *bufio.Reader - ) - - in, err := os.Open(selinuxConfig) - if err != nil { - return "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err != io.EOF { - return "" - } - done = true - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == target { - return strings.Trim(val, "\"") - } - } - } - return "" -} - -func getSELinuxPolicyRoot() string { - return selinuxDir + readConfig(selinuxTypeTag) -} - -func readCon(name string) (string, error) { - var val string - - in, err := os.Open(name) - if err != nil { - return "", err - } - defer in.Close() - - _, err = fmt.Fscanf(in, "%s", &val) - return val, err -} - -// Setfilecon sets the SELinux label for this path or returns an error. -func Setfilecon(path string, scon string) error { - return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0) -} - -// Getfilecon returns the SELinux label for this path or returns an error. -func Getfilecon(path string) (string, error) { - con, err := system.Lgetxattr(path, xattrNameSelinux) - if err != nil { - return "", err - } - // Trim the NUL byte at the end of the byte buffer, if present. - if len(con) > 0 && con[len(con)-1] == '\x00' { - con = con[:len(con)-1] - } - return string(con), nil -} - -func Setfscreatecon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), scon) -} - -func Getfscreatecon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid())) -} - -// Getcon returns the SELinux label of the current process thread, or an error. -func Getcon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid())) -} - -// Getpidcon returns the SELinux label of the given pid, or an error. -func Getpidcon(pid int) (string, error) { - return readCon(fmt.Sprintf("/proc/%d/attr/current", pid)) -} - -func Getexeccon() (string, error) { - return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) -} - -func writeCon(name string, val string) error { - out, err := os.OpenFile(name, os.O_WRONLY, 0) - if err != nil { - return err - } - defer out.Close() - - if val != "" { - _, err = out.Write([]byte(val)) - } else { - _, err = out.Write(nil) - } - return err -} - -func Setexeccon(scon string) error { - return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon) -} - -func (c SELinuxContext) Get() string { - return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"]) -} - -func NewContext(scon string) SELinuxContext { - c := make(SELinuxContext) - - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - c["user"] = con[0] - c["role"] = con[1] - c["type"] = con[2] - c["level"] = con[3] - } - return c -} - -func ReserveLabel(scon string) { - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - mcsAdd(con[3]) - } -} - -func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", selinuxPath) -} - -func SelinuxGetEnforce() int { - var enforce int - - enforceS, err := readCon(selinuxEnforcePath()) - if err != nil { - return -1 - } - - enforce, err = strconv.Atoi(string(enforceS)) - if err != nil { - return -1 - } - return enforce -} - -func SelinuxSetEnforce(mode int) error { - return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode)) -} - -func SelinuxGetEnforceMode() int { - switch readConfig(selinuxTag) { - case "enforcing": - return Enforcing - case "permissive": - return Permissive - } - return Disabled -} - -func mcsAdd(mcs string) error { - if mcsList[mcs] { - return fmt.Errorf("MCS Label already exists") - } - mcsList[mcs] = true - return nil -} - -func mcsDelete(mcs string) { - mcsList[mcs] = false -} - -func IntToMcs(id int, catRange uint32) string { - var ( - SETSIZE = int(catRange) - TIER = SETSIZE - ORD = id - ) - - if id < 1 || id > 523776 { - return "" - } - - for ORD > TIER { - ORD = ORD - TIER - TIER -= 1 - } - TIER = SETSIZE - TIER - ORD = ORD + TIER - return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) -} - -func uniqMcs(catRange uint32) string { - var ( - n uint32 - c1, c2 uint32 - mcs string - ) - - for { - binary.Read(rand.Reader, binary.LittleEndian, &n) - c1 = n % catRange - binary.Read(rand.Reader, binary.LittleEndian, &n) - c2 = n % catRange - if c1 == c2 { - continue - } else { - if c1 > c2 { - t := c1 - c1 = c2 - c2 = t - } - } - mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) - if err := mcsAdd(mcs); err != nil { - continue - } - break - } - return mcs -} - -func FreeLxcContexts(scon string) { - if len(scon) != 0 { - con := strings.SplitN(scon, ":", 4) - mcsDelete(con[3]) - } -} - -func GetLxcContexts() (processLabel string, fileLabel string) { - var ( - val, key string - bufin *bufio.Reader - ) - - if !SelinuxEnabled() { - return "", "" - } - lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot()) - in, err := os.Open(lxcPath) - if err != nil { - return "", "" - } - defer in.Close() - - bufin = bufio.NewReader(in) - - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err == io.EOF { - done = true - } else { - goto exit - } - } - line = strings.TrimSpace(line) - if len(line) == 0 { - // Skip blank lines - continue - } - if line[0] == ';' || line[0] == '#' { - // Skip comments - continue - } - if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) - if key == "process" { - processLabel = strings.Trim(val, "\"") - } - if key == "file" { - fileLabel = strings.Trim(val, "\"") - } - } - } - - if processLabel == "" || fileLabel == "" { - return "", "" - } - -exit: - // mcs := IntToMcs(os.Getpid(), 1024) - mcs := uniqMcs(1024) - scon := NewContext(processLabel) - scon["level"] = mcs - processLabel = scon.Get() - scon = NewContext(fileLabel) - scon["level"] = mcs - fileLabel = scon.Get() - return processLabel, fileLabel -} - -func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s.context", selinuxPath), val) -} - -func CopyLevel(src, dest string) (string, error) { - if src == "" { - return "", nil - } - if err := SecurityCheckContext(src); err != nil { - return "", err - } - if err := SecurityCheckContext(dest); err != nil { - return "", err - } - scon := NewContext(src) - tcon := NewContext(dest) - mcsDelete(tcon["level"]) - mcsAdd(scon["level"]) - tcon["level"] = scon["level"] - return tcon.Get(), nil -} - -// Prevent users from relabing system files -func badPrefix(fpath string) error { - var badprefixes = []string{"/usr"} - - for _, prefix := range badprefixes { - if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) { - return fmt.Errorf("Relabeling content in %s is not allowed.", prefix) - } - } - return nil -} - -// Change the fpath file object to the SELinux label scon. -// If the fpath is a directory and recurse is true Chcon will walk the -// directory tree setting the label -func Chcon(fpath string, scon string, recurse bool) error { - if scon == "" { - return nil - } - if err := badPrefix(fpath); err != nil { - return err - } - callback := func(p string, info os.FileInfo, err error) error { - return Setfilecon(p, scon) - } - - if recurse { - return filepath.Walk(fpath, callback) - } - - return Setfilecon(fpath, scon) -} - -// DupSecOpt takes an SELinux process label and returns security options that -// can will set the SELinux Type and Level for future container processes -func DupSecOpt(src string) []string { - if src == "" { - return nil - } - con := NewContext(src) - if con["user"] == "" || - con["role"] == "" || - con["type"] == "" || - con["level"] == "" { - return nil - } - return []string{"label:user:" + con["user"], - "label:role:" + con["role"], - "label:type:" + con["type"], - "label:level:" + con["level"]} -} - -// DisableSecOpt returns a security opt that can be used to disabling SELinux -// labeling support for future container processes -func DisableSecOpt() []string { - return []string{"label:disable"} -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go deleted file mode 100644 index c2d561bf5ff6c472a7470ccb152f5942b6f6fcae..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// +build linux,selinux - -package selinux_test - -import ( - "os" - "testing" - - "github.com/opencontainers/runc/libcontainer/selinux" -) - -func TestSetfilecon(t *testing.T) { - if selinux.SelinuxEnabled() { - tmp := "selinux_test" - out, _ := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0) - out.Close() - err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0") - if err != nil { - t.Log("Setfilecon failed") - t.Fatal(err) - } - os.Remove(tmp) - } -} - -func TestSELinux(t *testing.T) { - var ( - err error - plabel, flabel string - ) - - if selinux.SelinuxEnabled() { - t.Log("Enabled") - plabel, flabel = selinux.GetLxcContexts() - t.Log(plabel) - t.Log(flabel) - selinux.FreeLxcContexts(plabel) - plabel, flabel = selinux.GetLxcContexts() - t.Log(plabel) - t.Log(flabel) - selinux.FreeLxcContexts(plabel) - t.Log("getenforce ", selinux.SelinuxGetEnforce()) - mode := selinux.SelinuxGetEnforceMode() - t.Log("getenforcemode ", mode) - - defer selinux.SelinuxSetEnforce(mode) - if err := selinux.SelinuxSetEnforce(selinux.Enforcing); err != nil { - t.Fatalf("enforcing selinux failed: %v", err) - } - if err := selinux.SelinuxSetEnforce(selinux.Permissive); err != nil { - t.Fatalf("setting selinux mode to permissive failed: %v", err) - } - selinux.SelinuxSetEnforce(mode) - - pid := os.Getpid() - t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023)) - err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0") - if err == nil { - t.Log(selinux.Getfscreatecon()) - } else { - t.Log("setfscreatecon failed", err) - t.Fatal(err) - } - err = selinux.Setfscreatecon("") - if err == nil { - t.Log(selinux.Getfscreatecon()) - } else { - t.Log("setfscreatecon failed", err) - t.Fatal(err) - } - t.Log(selinux.Getpidcon(1)) - } else { - t.Log("Disabled") - } -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/setgroups_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/setgroups_linux.go deleted file mode 100644 index c7bdb605aa88a24cad730d04b01a6b5ab5095f80..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/setgroups_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build linux,go1.5 - -package libcontainer - -import "syscall" - -// Set the GidMappingsEnableSetgroups member to true, so the process's -// setgroups proc entry wont be set to 'deny' if GidMappings are set -func enableSetgroups(sys *syscall.SysProcAttr) { - sys.GidMappingsEnableSetgroups = true -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go index 33ef68e5aae3cb51b8801b808878e3f3533c0ccf..6613bb65cb582a5a54c895d2d6691a5b2e7872e0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -5,18 +5,24 @@ package libcontainer import ( "fmt" "os" + "runtime" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/keys" - "github.com/opencontainers/runc/libcontainer/label" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + + "golang.org/x/sys/unix" ) // linuxSetnsInit performs the container's initialization for running a new process // inside an existing container. type linuxSetnsInit struct { - config *initConfig + pipe *os.File + consoleSocket *os.File + config *initConfig } func (l *linuxSetnsInit) getSessionRingName() string { @@ -24,19 +30,42 @@ func (l *linuxSetnsInit) getSessionRingName() string { } func (l *linuxSetnsInit) Init() error { - // do not inherit the parent's session keyring - if _, err := keyctl.JoinSessionKeyring(l.getSessionRingName()); err != nil { - return err + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if !l.config.Config.NoNewKeyring { + // Do not inherit the parent's session keyring. + if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil { + // Same justification as in standart_init_linux.go as to why we + // don't bail on ENOSYS. + // + // TODO(cyphar): And we should have logging here too. + if errors.Cause(err) != unix.ENOSYS { + return errors.Wrap(err, "join session keyring") + } + } } - if err := setupRlimits(l.config.Rlimits); err != nil { - return err + if l.config.CreateConsole { + if err := setupConsole(l.consoleSocket, l.config, false); err != nil { + return err + } + if err := system.Setctty(); err != nil { + return err + } } if l.config.NoNewPrivileges { - if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { return err } } - if l.config.Config.Seccomp != nil { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { + return err + } + defer label.SetProcessLabel("") + // Without NoNewPrivileges seccomp is a privileged operation, so we need to + // do this before dropping capabilities; otherwise do it as late as possible + // just before execve so as few syscalls take place after it as possible. + if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { return err } @@ -47,9 +76,12 @@ func (l *linuxSetnsInit) Init() error { if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if l.config.ProcessLabel != "" { - if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { - return err + // Set seccomp as close to execve as possible, so as few syscalls take + // place afterward (reducing the amount of syscalls that users need to + // enable in their seccomp profiles). + if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return newSystemErrorWithCause(err, "init seccomp") } } return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go b/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go new file mode 100644 index 0000000000000000000000000000000000000000..827ca9e781d9b9bac199df9c1cac72253a7cf4d9 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go @@ -0,0 +1,221 @@ +package specconv + +import ( + "os" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// Example returns an example spec file, with many options set so a user can +// see what a standard spec file looks like. +func Example() *specs.Spec { + return &specs.Spec{ + Version: specs.Version, + Root: &specs.Root{ + Path: "rootfs", + Readonly: true, + }, + Process: &specs.Process{ + Terminal: true, + User: specs.User{}, + Args: []string{ + "sh", + }, + Env: []string{ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + }, + Cwd: "/", + NoNewPrivileges: true, + Capabilities: &specs.LinuxCapabilities{ + Bounding: []string{ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE", + }, + Permitted: []string{ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE", + }, + Inheritable: []string{ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE", + }, + Ambient: []string{ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE", + }, + Effective: []string{ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE", + }, + }, + Rlimits: []specs.POSIXRlimit{ + { + Type: "RLIMIT_NOFILE", + Hard: uint64(1024), + Soft: uint64(1024), + }, + }, + }, + Hostname: "runc", + Mounts: []specs.Mount{ + { + Destination: "/proc", + Type: "proc", + Source: "proc", + Options: nil, + }, + { + Destination: "/dev", + Type: "tmpfs", + Source: "tmpfs", + Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, + }, + { + Destination: "/dev/pts", + Type: "devpts", + Source: "devpts", + Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, + }, + { + Destination: "/dev/shm", + Type: "tmpfs", + Source: "shm", + Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, + }, + { + Destination: "/dev/mqueue", + Type: "mqueue", + Source: "mqueue", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/sys", + Type: "sysfs", + Source: "sysfs", + Options: []string{"nosuid", "noexec", "nodev", "ro"}, + }, + { + Destination: "/sys/fs/cgroup", + Type: "cgroup", + Source: "cgroup", + Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, + }, + }, + Linux: &specs.Linux{ + MaskedPaths: []string{ + "/proc/kcore", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/sys/firmware", + "/proc/scsi", + }, + ReadonlyPaths: []string{ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + }, + Resources: &specs.LinuxResources{ + Devices: []specs.LinuxDeviceCgroup{ + { + Allow: false, + Access: "rwm", + }, + }, + }, + Namespaces: []specs.LinuxNamespace{ + { + Type: "pid", + }, + { + Type: "network", + }, + { + Type: "ipc", + }, + { + Type: "uts", + }, + { + Type: "mount", + }, + }, + }, + } +} + +// ToRootless converts the given spec file into one that should work with +// rootless containers (euid != 0), by removing incompatible options and adding others that +// are needed. +func ToRootless(spec *specs.Spec) { + var namespaces []specs.LinuxNamespace + + // Remove networkns from the spec. + for _, ns := range spec.Linux.Namespaces { + switch ns.Type { + case specs.NetworkNamespace, specs.UserNamespace: + // Do nothing. + default: + namespaces = append(namespaces, ns) + } + } + // Add userns to the spec. + namespaces = append(namespaces, specs.LinuxNamespace{ + Type: specs.UserNamespace, + }) + spec.Linux.Namespaces = namespaces + + // Add mappings for the current user. + spec.Linux.UIDMappings = []specs.LinuxIDMapping{{ + HostID: uint32(os.Geteuid()), + ContainerID: 0, + Size: 1, + }} + spec.Linux.GIDMappings = []specs.LinuxIDMapping{{ + HostID: uint32(os.Getegid()), + ContainerID: 0, + Size: 1, + }} + + // Fix up mounts. + var mounts []specs.Mount + for _, mount := range spec.Mounts { + // Ignore all mounts that are under /sys. + if strings.HasPrefix(mount.Destination, "/sys") { + continue + } + + // Remove all gid= and uid= mappings. + var options []string + for _, option := range mount.Options { + if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") { + options = append(options, option) + } + } + + mount.Options = options + mounts = append(mounts, mount) + } + // Add the sysfs mount as an rbind. + mounts = append(mounts, specs.Mount{ + Source: "/sys", + Destination: "/sys", + Type: "none", + Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"}, + }) + spec.Mounts = mounts + + // Remove cgroup settings. + spec.Linux.Resources = nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..a15798923630acd6743f308ea15320056df95931 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go @@ -0,0 +1,837 @@ +// +build linux + +// Package specconv implements conversion of specifications to libcontainer +// configurations +package specconv + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/seccomp" + libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + + "golang.org/x/sys/unix" +) + +const wildcard = -1 + +var namespaceMapping = map[specs.LinuxNamespaceType]configs.NamespaceType{ + specs.PIDNamespace: configs.NEWPID, + specs.NetworkNamespace: configs.NEWNET, + specs.MountNamespace: configs.NEWNS, + specs.UserNamespace: configs.NEWUSER, + specs.IPCNamespace: configs.NEWIPC, + specs.UTSNamespace: configs.NEWUTS, + specs.CgroupNamespace: configs.NEWCGROUP, +} + +var mountPropagationMapping = map[string]int{ + "rprivate": unix.MS_PRIVATE | unix.MS_REC, + "private": unix.MS_PRIVATE, + "rslave": unix.MS_SLAVE | unix.MS_REC, + "slave": unix.MS_SLAVE, + "rshared": unix.MS_SHARED | unix.MS_REC, + "shared": unix.MS_SHARED, + "runbindable": unix.MS_UNBINDABLE | unix.MS_REC, + "unbindable": unix.MS_UNBINDABLE, + "": 0, +} + +var allowedDevices = []*configs.Device{ + // allow mknod for any device + { + Type: 'c', + Major: wildcard, + Minor: wildcard, + Permissions: "m", + Allow: true, + }, + { + Type: 'b', + Major: wildcard, + Minor: wildcard, + Permissions: "m", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/null", + Major: 1, + Minor: 3, + Permissions: "rwm", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/random", + Major: 1, + Minor: 8, + Permissions: "rwm", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/full", + Major: 1, + Minor: 7, + Permissions: "rwm", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/tty", + Major: 5, + Minor: 0, + Permissions: "rwm", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/zero", + Major: 1, + Minor: 5, + Permissions: "rwm", + Allow: true, + }, + { + Type: 'c', + Path: "/dev/urandom", + Major: 1, + Minor: 9, + Permissions: "rwm", + Allow: true, + }, + { + Path: "/dev/console", + Type: 'c', + Major: 5, + Minor: 1, + Permissions: "rwm", + Allow: true, + }, + // /dev/pts/ - pts namespaces are "coming soon" + { + Path: "", + Type: 'c', + Major: 136, + Minor: wildcard, + Permissions: "rwm", + Allow: true, + }, + { + Path: "", + Type: 'c', + Major: 5, + Minor: 2, + Permissions: "rwm", + Allow: true, + }, + // tuntap + { + Path: "", + Type: 'c', + Major: 10, + Minor: 200, + Permissions: "rwm", + Allow: true, + }, +} + +type CreateOpts struct { + CgroupName string + UseSystemdCgroup bool + NoPivotRoot bool + NoNewKeyring bool + Spec *specs.Spec + RootlessEUID bool + RootlessCgroups bool +} + +// CreateLibcontainerConfig creates a new libcontainer configuration from a +// given specification and a cgroup name +func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) { + // runc's cwd will always be the bundle path + rcwd, err := os.Getwd() + if err != nil { + return nil, err + } + cwd, err := filepath.Abs(rcwd) + if err != nil { + return nil, err + } + spec := opts.Spec + if spec.Root == nil { + return nil, fmt.Errorf("Root must be specified") + } + rootfsPath := spec.Root.Path + if !filepath.IsAbs(rootfsPath) { + rootfsPath = filepath.Join(cwd, rootfsPath) + } + labels := []string{} + for k, v := range spec.Annotations { + labels = append(labels, fmt.Sprintf("%s=%s", k, v)) + } + config := &configs.Config{ + Rootfs: rootfsPath, + NoPivotRoot: opts.NoPivotRoot, + Readonlyfs: spec.Root.Readonly, + Hostname: spec.Hostname, + Labels: append(labels, fmt.Sprintf("bundle=%s", cwd)), + NoNewKeyring: opts.NoNewKeyring, + RootlessEUID: opts.RootlessEUID, + RootlessCgroups: opts.RootlessCgroups, + } + + exists := false + for _, m := range spec.Mounts { + config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m)) + } + if err := createDevices(spec, config); err != nil { + return nil, err + } + c, err := createCgroupConfig(opts) + if err != nil { + return nil, err + } + config.Cgroups = c + // set linux-specific config + if spec.Linux != nil { + if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists { + return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation) + } + if config.NoPivotRoot && (config.RootPropagation&unix.MS_PRIVATE != 0) { + return nil, fmt.Errorf("rootfsPropagation of [r]private is not safe without pivot_root") + } + + for _, ns := range spec.Linux.Namespaces { + t, exists := namespaceMapping[ns.Type] + if !exists { + return nil, fmt.Errorf("namespace %q does not exist", ns) + } + if config.Namespaces.Contains(t) { + return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns) + } + config.Namespaces.Add(t, ns.Path) + } + if config.Namespaces.Contains(configs.NEWNET) && config.Namespaces.PathOf(configs.NEWNET) == "" { + config.Networks = []*configs.Network{ + { + Type: "loopback", + }, + } + } + if config.Namespaces.Contains(configs.NEWUSER) { + if err := setupUserNamespace(spec, config); err != nil { + return nil, err + } + } + config.MaskPaths = spec.Linux.MaskedPaths + config.ReadonlyPaths = spec.Linux.ReadonlyPaths + config.MountLabel = spec.Linux.MountLabel + config.Sysctl = spec.Linux.Sysctl + if spec.Linux.Seccomp != nil { + seccomp, err := SetupSeccomp(spec.Linux.Seccomp) + if err != nil { + return nil, err + } + config.Seccomp = seccomp + } + if spec.Linux.IntelRdt != nil { + config.IntelRdt = &configs.IntelRdt{} + if spec.Linux.IntelRdt.L3CacheSchema != "" { + config.IntelRdt.L3CacheSchema = spec.Linux.IntelRdt.L3CacheSchema + } + if spec.Linux.IntelRdt.MemBwSchema != "" { + config.IntelRdt.MemBwSchema = spec.Linux.IntelRdt.MemBwSchema + } + } + } + if spec.Process != nil { + config.OomScoreAdj = spec.Process.OOMScoreAdj + if spec.Process.SelinuxLabel != "" { + config.ProcessLabel = spec.Process.SelinuxLabel + } + if spec.Process.Capabilities != nil { + config.Capabilities = &configs.Capabilities{ + Bounding: spec.Process.Capabilities.Bounding, + Effective: spec.Process.Capabilities.Effective, + Permitted: spec.Process.Capabilities.Permitted, + Inheritable: spec.Process.Capabilities.Inheritable, + Ambient: spec.Process.Capabilities.Ambient, + } + } + } + createHooks(spec, config) + config.Version = specs.Version + return config, nil +} + +func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount { + flags, pgflags, data, ext := parseMountOptions(m.Options) + source := m.Source + device := m.Type + if flags&unix.MS_BIND != 0 { + if device == "" { + device = "bind" + } + if !filepath.IsAbs(source) { + source = filepath.Join(cwd, m.Source) + } + } + return &configs.Mount{ + Device: device, + Source: source, + Destination: m.Destination, + Data: data, + Flags: flags, + PropagationFlags: pgflags, + Extensions: ext, + } +} + +func createCgroupConfig(opts *CreateOpts) (*configs.Cgroup, error) { + var ( + myCgroupPath string + + spec = opts.Spec + useSystemdCgroup = opts.UseSystemdCgroup + name = opts.CgroupName + ) + + c := &configs.Cgroup{ + Resources: &configs.Resources{}, + } + + if spec.Linux != nil && spec.Linux.CgroupsPath != "" { + myCgroupPath = libcontainerUtils.CleanPath(spec.Linux.CgroupsPath) + if useSystemdCgroup { + myCgroupPath = spec.Linux.CgroupsPath + } + } + + if useSystemdCgroup { + if myCgroupPath == "" { + c.Parent = "system.slice" + c.ScopePrefix = "runc" + c.Name = name + } else { + // Parse the path from expected "slice:prefix:name" + // for e.g. "system.slice:docker:1234" + parts := strings.Split(myCgroupPath, ":") + if len(parts) != 3 { + return nil, fmt.Errorf("expected cgroupsPath to be of format \"slice:prefix:name\" for systemd cgroups") + } + c.Parent = parts[0] + c.ScopePrefix = parts[1] + c.Name = parts[2] + } + } else { + if myCgroupPath == "" { + c.Name = name + } + c.Path = myCgroupPath + } + + // In rootless containers, any attempt to make cgroup changes is likely to fail. + // libcontainer will validate this but ignores the error. + c.Resources.AllowedDevices = allowedDevices + if spec.Linux != nil { + r := spec.Linux.Resources + if r == nil { + return c, nil + } + for i, d := range spec.Linux.Resources.Devices { + var ( + t = "a" + major = int64(-1) + minor = int64(-1) + ) + if d.Type != "" { + t = d.Type + } + if d.Major != nil { + major = *d.Major + } + if d.Minor != nil { + minor = *d.Minor + } + if d.Access == "" { + return nil, fmt.Errorf("device access at %d field cannot be empty", i) + } + dt, err := stringToCgroupDeviceRune(t) + if err != nil { + return nil, err + } + dd := &configs.Device{ + Type: dt, + Major: major, + Minor: minor, + Permissions: d.Access, + Allow: d.Allow, + } + c.Resources.Devices = append(c.Resources.Devices, dd) + } + if r.Memory != nil { + if r.Memory.Limit != nil { + c.Resources.Memory = *r.Memory.Limit + } + if r.Memory.Reservation != nil { + c.Resources.MemoryReservation = *r.Memory.Reservation + } + if r.Memory.Swap != nil { + c.Resources.MemorySwap = *r.Memory.Swap + } + if r.Memory.Kernel != nil { + c.Resources.KernelMemory = *r.Memory.Kernel + } + if r.Memory.KernelTCP != nil { + c.Resources.KernelMemoryTCP = *r.Memory.KernelTCP + } + if r.Memory.Swappiness != nil { + c.Resources.MemorySwappiness = r.Memory.Swappiness + } + if r.Memory.DisableOOMKiller != nil { + c.Resources.OomKillDisable = *r.Memory.DisableOOMKiller + } + } + if r.CPU != nil { + if r.CPU.Shares != nil { + c.Resources.CpuShares = *r.CPU.Shares + } + if r.CPU.Quota != nil { + c.Resources.CpuQuota = *r.CPU.Quota + } + if r.CPU.Period != nil { + c.Resources.CpuPeriod = *r.CPU.Period + } + if r.CPU.RealtimeRuntime != nil { + c.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime + } + if r.CPU.RealtimePeriod != nil { + c.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod + } + if r.CPU.Cpus != "" { + c.Resources.CpusetCpus = r.CPU.Cpus + } + if r.CPU.Mems != "" { + c.Resources.CpusetMems = r.CPU.Mems + } + } + if r.Pids != nil { + c.Resources.PidsLimit = r.Pids.Limit + } + if r.BlockIO != nil { + if r.BlockIO.Weight != nil { + c.Resources.BlkioWeight = *r.BlockIO.Weight + } + if r.BlockIO.LeafWeight != nil { + c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight + } + if r.BlockIO.WeightDevice != nil { + for _, wd := range r.BlockIO.WeightDevice { + var weight, leafWeight uint16 + if wd.Weight != nil { + weight = *wd.Weight + } + if wd.LeafWeight != nil { + leafWeight = *wd.LeafWeight + } + weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, weight, leafWeight) + c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice) + } + } + if r.BlockIO.ThrottleReadBpsDevice != nil { + for _, td := range r.BlockIO.ThrottleReadBpsDevice { + rate := td.Rate + throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) + c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice) + } + } + if r.BlockIO.ThrottleWriteBpsDevice != nil { + for _, td := range r.BlockIO.ThrottleWriteBpsDevice { + rate := td.Rate + throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) + c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice) + } + } + if r.BlockIO.ThrottleReadIOPSDevice != nil { + for _, td := range r.BlockIO.ThrottleReadIOPSDevice { + rate := td.Rate + throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) + c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice) + } + } + if r.BlockIO.ThrottleWriteIOPSDevice != nil { + for _, td := range r.BlockIO.ThrottleWriteIOPSDevice { + rate := td.Rate + throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) + c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice) + } + } + } + for _, l := range r.HugepageLimits { + c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{ + Pagesize: l.Pagesize, + Limit: l.Limit, + }) + } + if r.Network != nil { + if r.Network.ClassID != nil { + c.Resources.NetClsClassid = *r.Network.ClassID + } + for _, m := range r.Network.Priorities { + c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{ + Interface: m.Name, + Priority: int64(m.Priority), + }) + } + } + } + // append the default allowed devices to the end of the list + c.Resources.Devices = append(c.Resources.Devices, allowedDevices...) + return c, nil +} + +func stringToCgroupDeviceRune(s string) (rune, error) { + switch s { + case "a": + return 'a', nil + case "b": + return 'b', nil + case "c": + return 'c', nil + default: + return 0, fmt.Errorf("invalid cgroup device type %q", s) + } +} + +func stringToDeviceRune(s string) (rune, error) { + switch s { + case "p": + return 'p', nil + case "u": + return 'u', nil + case "b": + return 'b', nil + case "c": + return 'c', nil + default: + return 0, fmt.Errorf("invalid device type %q", s) + } +} + +func createDevices(spec *specs.Spec, config *configs.Config) error { + // add whitelisted devices + config.Devices = []*configs.Device{ + { + Type: 'c', + Path: "/dev/null", + Major: 1, + Minor: 3, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + { + Type: 'c', + Path: "/dev/random", + Major: 1, + Minor: 8, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + { + Type: 'c', + Path: "/dev/full", + Major: 1, + Minor: 7, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + { + Type: 'c', + Path: "/dev/tty", + Major: 5, + Minor: 0, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + { + Type: 'c', + Path: "/dev/zero", + Major: 1, + Minor: 5, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + { + Type: 'c', + Path: "/dev/urandom", + Major: 1, + Minor: 9, + FileMode: 0666, + Uid: 0, + Gid: 0, + }, + } + // merge in additional devices from the spec + if spec.Linux != nil { + for _, d := range spec.Linux.Devices { + var uid, gid uint32 + var filemode os.FileMode = 0666 + + if d.UID != nil { + uid = *d.UID + } + if d.GID != nil { + gid = *d.GID + } + dt, err := stringToDeviceRune(d.Type) + if err != nil { + return err + } + if d.FileMode != nil { + filemode = *d.FileMode + } + device := &configs.Device{ + Type: dt, + Path: d.Path, + Major: d.Major, + Minor: d.Minor, + FileMode: filemode, + Uid: uid, + Gid: gid, + } + config.Devices = append(config.Devices, device) + } + } + return nil +} + +func setupUserNamespace(spec *specs.Spec, config *configs.Config) error { + create := func(m specs.LinuxIDMapping) configs.IDMap { + return configs.IDMap{ + HostID: int(m.HostID), + ContainerID: int(m.ContainerID), + Size: int(m.Size), + } + } + if spec.Linux != nil { + for _, m := range spec.Linux.UIDMappings { + config.UidMappings = append(config.UidMappings, create(m)) + } + for _, m := range spec.Linux.GIDMappings { + config.GidMappings = append(config.GidMappings, create(m)) + } + } + rootUID, err := config.HostRootUID() + if err != nil { + return err + } + rootGID, err := config.HostRootGID() + if err != nil { + return err + } + for _, node := range config.Devices { + node.Uid = uint32(rootUID) + node.Gid = uint32(rootGID) + } + return nil +} + +// parseMountOptions parses the string and returns the flags, propagation +// flags and any mount data that it contains. +func parseMountOptions(options []string) (int, []int, string, int) { + var ( + flag int + pgflag []int + data []string + extFlags int + ) + flags := map[string]struct { + clear bool + flag int + }{ + "acl": {false, unix.MS_POSIXACL}, + "async": {true, unix.MS_SYNCHRONOUS}, + "atime": {true, unix.MS_NOATIME}, + "bind": {false, unix.MS_BIND}, + "defaults": {false, 0}, + "dev": {true, unix.MS_NODEV}, + "diratime": {true, unix.MS_NODIRATIME}, + "dirsync": {false, unix.MS_DIRSYNC}, + "exec": {true, unix.MS_NOEXEC}, + "iversion": {false, unix.MS_I_VERSION}, + "lazytime": {false, unix.MS_LAZYTIME}, + "loud": {true, unix.MS_SILENT}, + "mand": {false, unix.MS_MANDLOCK}, + "noacl": {true, unix.MS_POSIXACL}, + "noatime": {false, unix.MS_NOATIME}, + "nodev": {false, unix.MS_NODEV}, + "nodiratime": {false, unix.MS_NODIRATIME}, + "noexec": {false, unix.MS_NOEXEC}, + "noiversion": {true, unix.MS_I_VERSION}, + "nolazytime": {true, unix.MS_LAZYTIME}, + "nomand": {true, unix.MS_MANDLOCK}, + "norelatime": {true, unix.MS_RELATIME}, + "nostrictatime": {true, unix.MS_STRICTATIME}, + "nosuid": {false, unix.MS_NOSUID}, + "rbind": {false, unix.MS_BIND | unix.MS_REC}, + "relatime": {false, unix.MS_RELATIME}, + "remount": {false, unix.MS_REMOUNT}, + "ro": {false, unix.MS_RDONLY}, + "rw": {true, unix.MS_RDONLY}, + "silent": {false, unix.MS_SILENT}, + "strictatime": {false, unix.MS_STRICTATIME}, + "suid": {true, unix.MS_NOSUID}, + "sync": {false, unix.MS_SYNCHRONOUS}, + } + propagationFlags := map[string]int{ + "private": unix.MS_PRIVATE, + "shared": unix.MS_SHARED, + "slave": unix.MS_SLAVE, + "unbindable": unix.MS_UNBINDABLE, + "rprivate": unix.MS_PRIVATE | unix.MS_REC, + "rshared": unix.MS_SHARED | unix.MS_REC, + "rslave": unix.MS_SLAVE | unix.MS_REC, + "runbindable": unix.MS_UNBINDABLE | unix.MS_REC, + } + extensionFlags := map[string]struct { + clear bool + flag int + }{ + "tmpcopyup": {false, configs.EXT_COPYUP}, + } + for _, o := range options { + // If the option does not exist in the flags table or the flag + // is not supported on the platform, + // then it is a data value for a specific fs type + if f, exists := flags[o]; exists && f.flag != 0 { + if f.clear { + flag &= ^f.flag + } else { + flag |= f.flag + } + } else if f, exists := propagationFlags[o]; exists && f != 0 { + pgflag = append(pgflag, f) + } else if f, exists := extensionFlags[o]; exists && f.flag != 0 { + if f.clear { + extFlags &= ^f.flag + } else { + extFlags |= f.flag + } + } else { + data = append(data, o) + } + } + return flag, pgflag, strings.Join(data, ","), extFlags +} + +func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) { + if config == nil { + return nil, nil + } + + // No default action specified, no syscalls listed, assume seccomp disabled + if config.DefaultAction == "" && len(config.Syscalls) == 0 { + return nil, nil + } + + newConfig := new(configs.Seccomp) + newConfig.Syscalls = []*configs.Syscall{} + + if len(config.Architectures) > 0 { + newConfig.Architectures = []string{} + for _, arch := range config.Architectures { + newArch, err := seccomp.ConvertStringToArch(string(arch)) + if err != nil { + return nil, err + } + newConfig.Architectures = append(newConfig.Architectures, newArch) + } + } + + // Convert default action from string representation + newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction)) + if err != nil { + return nil, err + } + newConfig.DefaultAction = newDefaultAction + + // Loop through all syscall blocks and convert them to libcontainer format + for _, call := range config.Syscalls { + newAction, err := seccomp.ConvertStringToAction(string(call.Action)) + if err != nil { + return nil, err + } + + for _, name := range call.Names { + newCall := configs.Syscall{ + Name: name, + Action: newAction, + Args: []*configs.Arg{}, + } + // Loop through all the arguments of the syscall and convert them + for _, arg := range call.Args { + newOp, err := seccomp.ConvertStringToOperator(string(arg.Op)) + if err != nil { + return nil, err + } + + newArg := configs.Arg{ + Index: arg.Index, + Value: arg.Value, + ValueTwo: arg.ValueTwo, + Op: newOp, + } + + newCall.Args = append(newCall.Args, &newArg) + } + newConfig.Syscalls = append(newConfig.Syscalls, &newCall) + } + } + + return newConfig, nil +} + +func createHooks(rspec *specs.Spec, config *configs.Config) { + config.Hooks = &configs.Hooks{} + if rspec.Hooks != nil { + + for _, h := range rspec.Hooks.Prestart { + cmd := createCommandHook(h) + config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd)) + } + for _, h := range rspec.Hooks.Poststart { + cmd := createCommandHook(h) + config.Hooks.Poststart = append(config.Hooks.Poststart, configs.NewCommandHook(cmd)) + } + for _, h := range rspec.Hooks.Poststop { + cmd := createCommandHook(h) + config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd)) + } + } +} + +func createCommandHook(h specs.Hook) configs.Command { + cmd := configs.Command{ + Path: h.Path, + Args: h.Args, + Env: h.Env, + } + if h.Timeout != nil { + d := time.Duration(*h.Timeout) * time.Second + cmd.Timeout = &d + } + return cmd +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux_test.go new file mode 100644 index 0000000000000000000000000000000000000000..50c620cbad6212c1ce8bbe46a07eef648ccb2a09 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux_test.go @@ -0,0 +1,450 @@ +// +build linux + +package specconv + +import ( + "os" + "strings" + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/configs/validate" + "github.com/opencontainers/runtime-spec/specs-go" +) + +func TestCreateCommandHookTimeout(t *testing.T) { + timeout := 3600 + hook := specs.Hook{ + Path: "/some/hook/path", + Args: []string{"--some", "thing"}, + Env: []string{"SOME=value"}, + Timeout: &timeout, + } + command := createCommandHook(hook) + timeoutStr := command.Timeout.String() + if timeoutStr != "1h0m0s" { + t.Errorf("Expected the Timeout to be 1h0m0s, got: %s", timeoutStr) + } +} + +func TestCreateHooks(t *testing.T) { + rspec := &specs.Spec{ + Hooks: &specs.Hooks{ + Prestart: []specs.Hook{ + { + Path: "/some/hook/path", + }, + { + Path: "/some/hook2/path", + Args: []string{"--some", "thing"}, + }, + }, + Poststart: []specs.Hook{ + { + Path: "/some/hook/path", + Args: []string{"--some", "thing"}, + Env: []string{"SOME=value"}, + }, + { + Path: "/some/hook2/path", + }, + { + Path: "/some/hook3/path", + }, + }, + Poststop: []specs.Hook{ + { + Path: "/some/hook/path", + Args: []string{"--some", "thing"}, + Env: []string{"SOME=value"}, + }, + { + Path: "/some/hook2/path", + }, + { + Path: "/some/hook3/path", + }, + { + Path: "/some/hook4/path", + Args: []string{"--some", "thing"}, + }, + }, + }, + } + conf := &configs.Config{} + createHooks(rspec, conf) + + prestart := conf.Hooks.Prestart + + if len(prestart) != 2 { + t.Error("Expected 2 Prestart hooks") + } + + poststart := conf.Hooks.Poststart + + if len(poststart) != 3 { + t.Error("Expected 3 Poststart hooks") + } + + poststop := conf.Hooks.Poststop + + if len(poststop) != 4 { + t.Error("Expected 4 Poststop hooks") + } + +} +func TestSetupSeccomp(t *testing.T) { + conf := &specs.LinuxSeccomp{ + DefaultAction: "SCMP_ACT_ERRNO", + Architectures: []specs.Arch{specs.ArchX86_64, specs.ArchARM}, + Syscalls: []specs.LinuxSyscall{ + { + Names: []string{"clone"}, + Action: "SCMP_ACT_ALLOW", + Args: []specs.LinuxSeccompArg{ + { + Index: 0, + Value: 2080505856, + ValueTwo: 0, + Op: "SCMP_CMP_MASKED_EQ", + }, + }, + }, + { + Names: []string{ + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "send", + "sendfile", + }, + Action: "SCMP_ACT_ALLOW", + }, + }, + } + seccomp, err := SetupSeccomp(conf) + + if err != nil { + t.Errorf("Couldn't create Seccomp config: %v", err) + } + + if seccomp.DefaultAction != 2 { // SCMP_ACT_ERRNO + t.Error("Wrong conversion for DefaultAction") + } + + if len(seccomp.Architectures) != 2 { + t.Error("Wrong number of architectures") + } + + if seccomp.Architectures[0] != "amd64" || seccomp.Architectures[1] != "arm" { + t.Error("Expected architectures are not found") + } + + calls := seccomp.Syscalls + + callsLength := len(calls) + if callsLength != 8 { + t.Errorf("Expected 8 syscalls, got :%d", callsLength) + } + + for i, call := range calls { + if i == 0 { + expectedCloneSyscallArgs := configs.Arg{ + Index: 0, + Op: 7, // SCMP_CMP_MASKED_EQ + Value: 2080505856, + ValueTwo: 0, + } + if expectedCloneSyscallArgs != *call.Args[0] { + t.Errorf("Wrong arguments conversion for the clone syscall under test") + } + } + if call.Action != 4 { + t.Error("Wrong conversion for the clone syscall action") + } + + } + +} + +func TestLinuxCgroupWithMemoryResource(t *testing.T) { + cgroupsPath := "/user/cgroups/path/id" + + spec := &specs.Spec{} + devices := []specs.LinuxDeviceCgroup{ + { + Allow: false, + Access: "rwm", + }, + } + + limit := int64(100) + reservation := int64(50) + swap := int64(20) + kernel := int64(40) + kernelTCP := int64(45) + swappiness := uint64(1) + swappinessPtr := &swappiness + disableOOMKiller := true + resources := &specs.LinuxResources{ + Devices: devices, + Memory: &specs.LinuxMemory{ + Limit: &limit, + Reservation: &reservation, + Swap: &swap, + Kernel: &kernel, + KernelTCP: &kernelTCP, + Swappiness: swappinessPtr, + DisableOOMKiller: &disableOOMKiller, + }, + } + spec.Linux = &specs.Linux{ + CgroupsPath: cgroupsPath, + Resources: resources, + } + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: false, + Spec: spec, + } + + cgroup, err := createCgroupConfig(opts) + if err != nil { + t.Errorf("Couldn't create Cgroup config: %v", err) + } + + if cgroup.Path != cgroupsPath { + t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path) + } + if cgroup.Resources.Memory != limit { + t.Errorf("Expected to have %d as memory limit, got %d", limit, cgroup.Resources.Memory) + } + if cgroup.Resources.MemoryReservation != reservation { + t.Errorf("Expected to have %d as memory reservation, got %d", reservation, cgroup.Resources.MemoryReservation) + } + if cgroup.Resources.MemorySwap != swap { + t.Errorf("Expected to have %d as swap, got %d", swap, cgroup.Resources.MemorySwap) + } + if cgroup.Resources.KernelMemory != kernel { + t.Errorf("Expected to have %d as Kernel Memory, got %d", kernel, cgroup.Resources.KernelMemory) + } + if cgroup.Resources.KernelMemoryTCP != kernelTCP { + t.Errorf("Expected to have %d as TCP Kernel Memory, got %d", kernelTCP, cgroup.Resources.KernelMemoryTCP) + } + if cgroup.Resources.MemorySwappiness != swappinessPtr { + t.Errorf("Expected to have %d as memory swappiness, got %d", swappinessPtr, cgroup.Resources.MemorySwappiness) + } + if cgroup.Resources.OomKillDisable != disableOOMKiller { + t.Errorf("The OOMKiller should be enabled") + } +} + +func TestLinuxCgroupSystemd(t *testing.T) { + cgroupsPath := "parent:scopeprefix:name" + + spec := &specs.Spec{} + spec.Linux = &specs.Linux{ + CgroupsPath: cgroupsPath, + } + + opts := &CreateOpts{ + UseSystemdCgroup: true, + Spec: spec, + } + + cgroup, err := createCgroupConfig(opts) + + if err != nil { + t.Errorf("Couldn't create Cgroup config: %v", err) + } + + expectedParent := "parent" + if cgroup.Parent != expectedParent { + t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent) + } + + expectedScopePrefix := "scopeprefix" + if cgroup.ScopePrefix != expectedScopePrefix { + t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix) + } + + expectedName := "name" + if cgroup.Name != expectedName { + t.Errorf("Expected to have %s as Name instead of %s", expectedName, cgroup.Name) + } +} + +func TestLinuxCgroupSystemdWithEmptyPath(t *testing.T) { + cgroupsPath := "" + + spec := &specs.Spec{} + spec.Linux = &specs.Linux{ + CgroupsPath: cgroupsPath, + } + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: true, + Spec: spec, + } + + cgroup, err := createCgroupConfig(opts) + + if err != nil { + t.Errorf("Couldn't create Cgroup config: %v", err) + } + + expectedParent := "system.slice" + if cgroup.Parent != expectedParent { + t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent) + } + + expectedScopePrefix := "runc" + if cgroup.ScopePrefix != expectedScopePrefix { + t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix) + } + + if cgroup.Name != opts.CgroupName { + t.Errorf("Expected to have %s as Name instead of %s", opts.CgroupName, cgroup.Name) + } +} + +func TestLinuxCgroupSystemdWithInvalidPath(t *testing.T) { + cgroupsPath := "/user/cgroups/path/id" + + spec := &specs.Spec{} + spec.Linux = &specs.Linux{ + CgroupsPath: cgroupsPath, + } + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: true, + Spec: spec, + } + + _, err := createCgroupConfig(opts) + if err == nil { + t.Error("Expected to produce an error if not using the correct format for cgroup paths belonging to systemd") + } +} +func TestLinuxCgroupsPathSpecified(t *testing.T) { + cgroupsPath := "/user/cgroups/path/id" + + spec := &specs.Spec{} + spec.Linux = &specs.Linux{ + CgroupsPath: cgroupsPath, + } + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: false, + Spec: spec, + } + + cgroup, err := createCgroupConfig(opts) + if err != nil { + t.Errorf("Couldn't create Cgroup config: %v", err) + } + + if cgroup.Path != cgroupsPath { + t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path) + } +} + +func TestLinuxCgroupsPathNotSpecified(t *testing.T) { + spec := &specs.Spec{} + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: false, + Spec: spec, + } + + cgroup, err := createCgroupConfig(opts) + if err != nil { + t.Errorf("Couldn't create Cgroup config: %v", err) + } + + if cgroup.Path != "" { + t.Errorf("Wrong cgroupsPath, expected it to be empty string, got '%s'", cgroup.Path) + } +} + +func TestSpecconvExampleValidate(t *testing.T) { + spec := Example() + spec.Root.Path = "/" + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: false, + Spec: spec, + } + + config, err := CreateLibcontainerConfig(opts) + if err != nil { + t.Errorf("Couldn't create libcontainer config: %v", err) + } + + validator := validate.New() + if err := validator.Validate(config); err != nil { + t.Errorf("Expected specconv to produce valid container config: %v", err) + } +} + +func TestDupNamespaces(t *testing.T) { + spec := &specs.Spec{ + Root: &specs.Root{ + Path: "rootfs", + }, + Linux: &specs.Linux{ + Namespaces: []specs.LinuxNamespace{ + { + Type: "pid", + }, + { + Type: "pid", + Path: "/proc/1/ns/pid", + }, + }, + }, + } + + _, err := CreateLibcontainerConfig(&CreateOpts{ + Spec: spec, + }) + + if !strings.Contains(err.Error(), "malformed spec file: duplicated ns") { + t.Errorf("Duplicated namespaces should be forbidden") + } +} + +func TestNonZeroEUIDCompatibleSpecconvValidate(t *testing.T) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + t.Skip("userns is unsupported") + } + + spec := Example() + spec.Root.Path = "/" + ToRootless(spec) + + opts := &CreateOpts{ + CgroupName: "ContainerID", + UseSystemdCgroup: false, + Spec: spec, + RootlessEUID: true, + RootlessCgroups: true, + } + + config, err := CreateLibcontainerConfig(opts) + if err != nil { + t.Errorf("Couldn't create libcontainer config: %v", err) + } + + validator := validate.New() + if err := validator.Validate(config); err != nil { + t.Errorf("Expected specconv to produce valid rootless container config: %v", err) + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go index 5ee6e37a3a4d2baa5ca735b046f5deb1c8574ee3..0bbe1495040923cc6f4566b7b3416260ca4464bf 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go @@ -2,14 +2,14 @@ package stacktrace import "runtime" -// Caputure captures a stacktrace for the current calling go program +// Capture captures a stacktrace for the current calling go program // // skip is the number of frames to skip func Capture(userSkip int) Stacktrace { var ( skip = userSkip + 1 // add one for our own function frames []Frame - prevPc uintptr = 0 + prevPc uintptr ) for i := skip; ; i++ { pc, file, line, ok := runtime.Caller(i) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go index 7e99a2661a9aca4ba4d01381b57769a56a737c50..978f6c408adba075ecf7303e5ff95666006e8b83 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture_test.go @@ -19,9 +19,9 @@ func TestCaptureTestFunc(t *testing.T) { // the first frame is the caller frame := stack.Frames[0] if expected := "captureFunc"; frame.Function != expected { - t.Fatalf("expteced function %q but recevied %q", expected, frame.Function) + t.Fatalf("expected function %q but received %q", expected, frame.Function) } - expected := "github.com/opencontainers/runc/libcontainer/stacktrace" + expected := "/runc/libcontainer/stacktrace" if !strings.HasSuffix(frame.Package, expected) { t.Fatalf("expected package %q but received %q", expected, frame.Package) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go index 2e10150539b4b43aa8fae8ceecd3cbcca4933bc4..ad7ee8d8c8a6eba1885208aec691853de5030b47 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -4,129 +4,152 @@ package libcontainer import ( "fmt" - "io" "os" - "syscall" + "os/exec" + "runtime" + "syscall" //only for Exec "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/keys" - "github.com/opencontainers/runc/libcontainer/label" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + + "golang.org/x/sys/unix" ) type linuxStandardInit struct { - pipe io.ReadWriter - parentPid int - config *initConfig + pipe *os.File + consoleSocket *os.File + parentPid int + fifoFd int + config *initConfig } func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) { var newperms uint32 if l.config.Config.Namespaces.Contains(configs.NEWUSER) { - // with user ns we need 'other' search permissions + // With user ns we need 'other' search permissions. newperms = 0x8 } else { - // without user ns we need 'UID' search permissions + // Without user ns we need 'UID' search permissions. newperms = 0x80000 } - // create a unique per session container name that we can - // join in setns; however, other containers can also join it + // Create a unique per session container name that we can join in setns; + // However, other containers can also join it. return fmt.Sprintf("_ses.%s", l.config.ContainerId), 0xffffffff, newperms } -// PR_SET_NO_NEW_PRIVS isn't exposed in Golang so we define it ourselves copying the value -// the kernel -const PR_SET_NO_NEW_PRIVS = 0x26 - func (l *linuxStandardInit) Init() error { - ringname, keepperms, newperms := l.getSessionRingParams() + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if !l.config.Config.NoNewKeyring { + ringname, keepperms, newperms := l.getSessionRingParams() - // do not inherit the parent's session keyring - sessKeyId, err := keyctl.JoinSessionKeyring(ringname) - if err != nil { - return err - } - // make session keyring searcheable - if err := keyctl.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { - return err - } - - var console *linuxConsole - if l.config.Console != "" { - console = newConsoleFromPath(l.config.Console) - if err := console.dupStdio(); err != nil { - return err - } - } - if console != nil { - if err := system.Setctty(); err != nil { - return err + // Do not inherit the parent's session keyring. + if sessKeyId, err := keys.JoinSessionKeyring(ringname); err != nil { + // If keyrings aren't supported then it is likely we are on an + // older kernel (or inside an LXC container). While we could bail, + // the security feature we are using here is best-effort (it only + // really provides marginal protection since VFS credentials are + // the only significant protection of keyrings). + // + // TODO(cyphar): Log this so people know what's going on, once we + // have proper logging in 'runc init'. + if errors.Cause(err) != unix.ENOSYS { + return errors.Wrap(err, "join session keyring") + } + } else { + // Make session keyring searcheable. If we've gotten this far we + // bail on any error -- we don't want to have a keyring with bad + // permissions. + if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { + return errors.Wrap(err, "mod keyring permissions") + } } } + if err := setupNetwork(l.config); err != nil { return err } if err := setupRoute(l.config.Config); err != nil { return err } - if err := setupRlimits(l.config.Rlimits); err != nil { + + label.Init() + if err := prepareRootfs(l.pipe, l.config); err != nil { return err } + // Set up the console. This has to be done *before* we finalize the rootfs, + // but *after* we've given the user the chance to set up all of the mounts + // they wanted. + if l.config.CreateConsole { + if err := setupConsole(l.consoleSocket, l.config, true); err != nil { + return err + } + if err := system.Setctty(); err != nil { + return errors.Wrap(err, "setctty") + } + } - label.Init() - // InitializeMountNamespace() can be executed only for a new mount namespace + // Finish the rootfs setup. if l.config.Config.Namespaces.Contains(configs.NEWNS) { - if err := setupRootfs(l.config.Config, console, l.pipe); err != nil { + if err := finalizeRootfs(l.config.Config); err != nil { return err } } + if hostname := l.config.Config.Hostname; hostname != "" { - if err := syscall.Sethostname([]byte(hostname)); err != nil { - return err + if err := unix.Sethostname([]byte(hostname)); err != nil { + return errors.Wrap(err, "sethostname") } } if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { - return err - } - if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { - return err + return errors.Wrap(err, "apply apparmor profile") } for key, value := range l.config.Config.Sysctl { if err := writeSystemProperty(key, value); err != nil { - return err + return errors.Wrapf(err, "write sysctl key %s", key) } } for _, path := range l.config.Config.ReadonlyPaths { - if err := remountReadonly(path); err != nil { - return err + if err := readonlyPath(path); err != nil { + return errors.Wrapf(err, "readonly path %s", path) } } for _, path := range l.config.Config.MaskPaths { - if err := maskFile(path); err != nil { - return err + if err := maskPath(path, l.config.Config.MountLabel); err != nil { + return errors.Wrapf(err, "mask path %s", path) } } pdeath, err := system.GetParentDeathSignal() if err != nil { - return err + return errors.Wrap(err, "get pdeath signal") } if l.config.NoNewPrivileges { - if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { - return err + if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + return errors.Wrap(err, "set nonewprivileges") } } // Tell our parent that we're ready to Execv. This must be done before the // Seccomp rules have been applied, because we need to be able to read and // write to a socket. if err := syncParentReady(l.pipe); err != nil { - return err + return errors.Wrap(err, "sync ready") } - if l.config.Config.Seccomp != nil { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { + return errors.Wrap(err, "set process label") + } + defer label.SetProcessLabel("") + // Without NoNewPrivileges seccomp is a privileged operation, so we need to + // do this before dropping capabilities; otherwise do it as late as possible + // just before execve so as few syscalls take place after it as possible. + if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { return err } @@ -137,14 +160,51 @@ func (l *linuxStandardInit) Init() error { // finalizeNamespace can change user/group which clears the parent death // signal, so we restore it here. if err := pdeath.Restore(); err != nil { + return errors.Wrap(err, "restore pdeath signal") + } + // Compare the parent from the initial start of the init process and make + // sure that it did not change. if the parent changes that means it died + // and we were reparented to something else so we should just kill ourself + // and not cause problems for someone else. + if unix.Getppid() != l.parentPid { + return unix.Kill(unix.Getpid(), unix.SIGKILL) + } + // Check for the arg before waiting to make sure it exists and it is + // returned as a create time error. + name, err := exec.LookPath(l.config.Args[0]) + if err != nil { return err } - // compare the parent from the inital start of the init process and make sure that it did not change. - // if the parent changes that means it died and we were reparened to something else so we should - // just kill ourself and not cause problems for someone else. - if syscall.Getppid() != l.parentPid { - return syscall.Kill(syscall.Getpid(), syscall.SIGKILL) + // Close the pipe to signal that we have completed our init. + l.pipe.Close() + // Wait for the FIFO to be opened on the other side before exec-ing the + // user process. We open it through /proc/self/fd/$fd, because the fd that + // was given to us was an O_PATH fd to the fifo itself. Linux allows us to + // re-open an O_PATH fd through /proc. + fd, err := unix.Open(fmt.Sprintf("/proc/self/fd/%d", l.fifoFd), unix.O_WRONLY|unix.O_CLOEXEC, 0) + if err != nil { + return newSystemErrorWithCause(err, "open exec fifo") + } + if _, err := unix.Write(fd, []byte("0")); err != nil { + return newSystemErrorWithCause(err, "write 0 exec fifo") + } + // Close the O_PATH fifofd fd before exec because the kernel resets + // dumpable in the wrong order. This has been fixed in newer kernels, but + // we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels. + // N.B. the core issue itself (passing dirfds to the host filesystem) has + // since been resolved. + // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 + unix.Close(l.fifoFd) + // Set seccomp as close to execve as possible, so as few syscalls take + // place afterward (reducing the amount of syscalls that users need to + // enable in their seccomp profiles). + if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return newSystemErrorWithCause(err, "init seccomp") + } } - - return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) + if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil { + return newSystemErrorWithCause(err, "exec user process") + } + return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go index 1813172bf603a6cbbdb8ab1d325fa41df108f6f4..5c16a423f741ffb7167758988b50503e86999368 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go @@ -7,8 +7,10 @@ import ( "os" "path/filepath" - "github.com/sirupsen/logrus" "github.com/opencontainers/runc/libcontainer/configs" + + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) func newStateTransitionError(from, to containerState) error { @@ -37,11 +39,16 @@ type containerState interface { func destroy(c *linuxContainer) error { if !c.config.Namespaces.Contains(configs.NEWPID) { - if err := killCgroupProcesses(c.cgroupManager); err != nil { + if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil { logrus.Warn(err) } } err := c.cgroupManager.Destroy() + if c.intelRdtManager != nil { + if ierr := c.intelRdtManager.Destroy(); err == nil { + err = ierr + } + } if rerr := os.RemoveAll(c.root); err == nil { err = rerr } @@ -55,10 +62,9 @@ func destroy(c *linuxContainer) error { func runPoststopHooks(c *linuxContainer) error { if c.config.Hooks != nil { - s := configs.HookState{ - Version: c.config.Version, - ID: c.id, - Root: c.config.Rootfs, + s, err := c.currentOCIState() + if err != nil { + return err } for _, hook := range c.config.Hooks.Poststop { if err := hook.Run(s); err != nil { @@ -75,15 +81,12 @@ type stoppedState struct { } func (b *stoppedState) status() Status { - return Destroyed + return Stopped } func (b *stoppedState) transition(s containerState) error { switch s.(type) { - case *runningState: - b.c.state = s - return nil - case *restoredState: + case *runningState, *restoredState: b.c.state = s return nil case *stoppedState: @@ -108,11 +111,11 @@ func (r *runningState) status() Status { func (r *runningState) transition(s containerState) error { switch s.(type) { case *stoppedState: - running, err := r.c.isRunning() + t, err := r.c.runType() if err != nil { return err } - if running { + if t == Running { return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped) } r.c.state = s @@ -127,16 +130,40 @@ func (r *runningState) transition(s containerState) error { } func (r *runningState) destroy() error { - running, err := r.c.isRunning() + t, err := r.c.runType() if err != nil { return err } - if running { + if t == Running { return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped) } return destroy(r.c) } +type createdState struct { + c *linuxContainer +} + +func (i *createdState) status() Status { + return Created +} + +func (i *createdState) transition(s containerState) error { + switch s.(type) { + case *runningState, *pausedState, *stoppedState: + i.c.state = s + return nil + case *createdState: + return nil + } + return newStateTransitionError(i, s) +} + +func (i *createdState) destroy() error { + i.c.initProcess.signal(unix.SIGKILL) + return destroy(i.c) +} + // pausedState represents a container that is currently pause. It cannot be destroyed in a // paused state and must transition back to running first. type pausedState struct { @@ -159,11 +186,11 @@ func (p *pausedState) transition(s containerState) error { } func (p *pausedState) destroy() error { - isRunning, err := p.c.isRunning() + t, err := p.c.runType() if err != nil { return err } - if !isRunning { + if t != Running && t != Created { if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil { return err } @@ -172,8 +199,8 @@ func (p *pausedState) destroy() error { return newGenericError(fmt.Errorf("container is paused"), ContainerPaused) } -// restoredState is the same as the running state but also has accociated checkpoint -// information that maybe need destroyed when the container is stopped and destory is called. +// restoredState is the same as the running state but also has associated checkpoint +// information that maybe need destroyed when the container is stopped and destroy is called. type restoredState struct { imageDir string c *linuxContainer @@ -185,9 +212,7 @@ func (r *restoredState) status() Status { func (r *restoredState) transition(s containerState) error { switch s.(type) { - case *stoppedState: - return nil - case *runningState: + case *stoppedState, *runningState: return nil } return newStateTransitionError(r, s) @@ -202,23 +227,23 @@ func (r *restoredState) destroy() error { return destroy(r.c) } -// createdState is used whenever a container is restored, loaded, or setting additional +// loadedState is used whenever a container is restored, loaded, or setting additional // processes inside and it should not be destroyed when it is exiting. -type createdState struct { +type loadedState struct { c *linuxContainer s Status } -func (n *createdState) status() Status { +func (n *loadedState) status() Status { return n.s } -func (n *createdState) transition(s containerState) error { +func (n *loadedState) transition(s containerState) error { n.c.state = s return nil } -func (n *createdState) destroy() error { +func (n *loadedState) destroy() error { if err := n.c.refreshState(); err != nil { return err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/state_linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/state_linux_test.go index 417d9c22eda68b45a888bdd9af5b213ab6483cbd..6ef516b757acb314cd4f1245ef50d6b23f994fce 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/state_linux_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/state_linux_test.go @@ -2,15 +2,21 @@ package libcontainer -import "testing" +import ( + "reflect" + "testing" +) + +var states = map[containerState]Status{ + &createdState{}: Created, + &runningState{}: Running, + &restoredState{}: Running, + &pausedState{}: Paused, + &stoppedState{}: Stopped, + &loadedState{s: Running}: Running, +} func TestStateStatus(t *testing.T) { - states := map[containerState]Status{ - &stoppedState{}: Destroyed, - &runningState{}: Running, - &restoredState{}: Running, - &pausedState{}: Paused, - } for s, status := range states { if s.status() != status { t.Fatalf("state returned %s but expected %s", s.status(), status) @@ -23,57 +29,88 @@ func isStateTransitionError(err error) bool { return ok } -func TestStoppedStateTransition(t *testing.T) { - s := &stoppedState{c: &linuxContainer{}} - valid := []containerState{ - &stoppedState{}, - &runningState{}, - &restoredState{}, +func testTransitions(t *testing.T, initialState containerState, valid []containerState) { + validMap := map[reflect.Type]interface{}{} + for _, validState := range valid { + validMap[reflect.TypeOf(validState)] = nil + t.Run(validState.status().String(), func(t *testing.T) { + if err := initialState.transition(validState); err != nil { + t.Fatal(err) + } + }) } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) + for state := range states { + if _, ok := validMap[reflect.TypeOf(state)]; ok { + continue } - } - err := s.transition(&pausedState{}) - if err == nil { - t.Fatal("transition to paused state should fail") - } - if !isStateTransitionError(err) { - t.Fatal("expected stateTransitionError") + t.Run(state.status().String(), func(t *testing.T) { + err := initialState.transition(state) + if err == nil { + t.Fatal("transition should fail") + } + if !isStateTransitionError(err) { + t.Fatal("expected stateTransitionError") + } + }) } } +func TestStoppedStateTransition(t *testing.T) { + testTransitions( + t, + &stoppedState{c: &linuxContainer{}}, + []containerState{ + &stoppedState{}, + &runningState{}, + &restoredState{}, + }, + ) +} + func TestPausedStateTransition(t *testing.T) { - s := &pausedState{c: &linuxContainer{}} - valid := []containerState{ - &pausedState{}, - &runningState{}, - &stoppedState{}, - } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) - } - } + testTransitions( + t, + &pausedState{c: &linuxContainer{}}, + []containerState{ + &pausedState{}, + &runningState{}, + &stoppedState{}, + }, + ) } func TestRestoredStateTransition(t *testing.T) { - s := &restoredState{c: &linuxContainer{}} - valid := []containerState{ - &stoppedState{}, - &runningState{}, - } - for _, v := range valid { - if err := s.transition(v); err != nil { - t.Fatal(err) - } - } - err := s.transition(&createdState{}) - if err == nil { - t.Fatal("transition to created state should fail") - } - if !isStateTransitionError(err) { - t.Fatal("expected stateTransitionError") - } + testTransitions( + t, + &restoredState{c: &linuxContainer{}}, + []containerState{ + &stoppedState{}, + &runningState{}, + }, + ) +} + +func TestRunningStateTransition(t *testing.T) { + testTransitions( + t, + &runningState{c: &linuxContainer{}}, + []containerState{ + &stoppedState{}, + &pausedState{}, + &runningState{}, + }, + ) +} + +func TestCreatedStateTransition(t *testing.T) { + testTransitions( + t, + &createdState{c: &linuxContainer{}}, + []containerState{ + &stoppedState{}, + &pausedState{}, + &runningState{}, + &createdState{}, + }, + ) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stats_freebsd.go b/vendor/github.com/opencontainers/runc/libcontainer/stats_freebsd.go deleted file mode 100644 index f8d1d689ceea6049411b02e4d0e924e8580a5c15..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/stats_freebsd.go +++ /dev/null @@ -1,5 +0,0 @@ -package libcontainer - -type Stats struct { - Interfaces []*NetworkInterface -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go index c629dc67de96df8426456ce87bca3c889f5decf4..29fd641e9dd1079b62177f0d197861d7873cd887 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go @@ -1,8 +1,10 @@ package libcontainer import "github.com/opencontainers/runc/libcontainer/cgroups" +import "github.com/opencontainers/runc/libcontainer/intelrdt" type Stats struct { - Interfaces []*NetworkInterface - CgroupStats *cgroups.Stats + Interfaces []*NetworkInterface + CgroupStats *cgroups.Stats + IntelRdtStats *intelrdt.Stats } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/stats_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/stats_windows.go deleted file mode 100644 index f8d1d689ceea6049411b02e4d0e924e8580a5c15..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/stats_windows.go +++ /dev/null @@ -1,5 +0,0 @@ -package libcontainer - -type Stats struct { - Interfaces []*NetworkInterface -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/sync.go b/vendor/github.com/opencontainers/runc/libcontainer/sync.go new file mode 100644 index 0000000000000000000000000000000000000000..a8704a2679df9678cbfcc43232c97cf271f77797 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/sync.go @@ -0,0 +1,104 @@ +package libcontainer + +import ( + "encoding/json" + "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 a &genericError). +// +// [ child ] <-> [ parent ] +// +// procHooks --> [run hooks] +// <-- procResume +// +// procConsole --> +// <-- procConsoleReq +// [send(fd)] --> [recv(fd)] +// <-- procConsoleAck +// +// 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"` +} + +// 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 a genericError, 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 err == io.EOF { + return fmt.Errorf("parent closed synchronisation channel") + } + + if procSync.Type == procError { + var ierr genericError + + if err := json.NewDecoder(pipe).Decode(&ierr); err != nil { + return fmt.Errorf("failed reading error from parent: %v", err) + } + + return &ierr + } + + if procSync.Type != expected { + return fmt.Errorf("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 err == io.EOF { + break + } + return err + } + + // We handle this case outside fn for cleanliness reasons. + var ierr *genericError + if sync.Type == procError { + if err := dec.Decode(&ierr); err != nil && err != io.EOF { + return newSystemErrorWithCause(err, "decoding proc error from init") + } + if ierr != nil { + return ierr + } + // Programmer error. + panic("No error following JSON procError payload.") + } + + if err := fn(&sync); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go index babf55048b805bf9e174a0ccf410a2e07e714590..a4ae8901acc06c79331c32615c24c3b913e26f92 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go @@ -3,14 +3,28 @@ package system import ( - "bufio" - "fmt" "os" "os/exec" - "syscall" + "syscall" // only for exec "unsafe" + + "github.com/opencontainers/runc/libcontainer/user" + "golang.org/x/sys/unix" ) +// If arg2 is nonzero, set the "child subreaper" attribute of the +// calling process; if arg2 is zero, unset the attribute. When a +// process is marked as a child subreaper, all of the children +// that it creates, and their descendants, will be marked as +// having a subreaper. In effect, a subreaper fulfills the role +// of init(1) for its descendant processes. Upon termination of +// a process that is orphaned (i.e., its immediate parent has +// already terminated) and marked as having a subreaper, the +// nearest still living ancestor subreaper will receive a SIGCHLD +// signal and be able to wait(2) on the process to discover its +// termination status. +const PR_SET_CHILD_SUBREAPER = 36 + type ParentDeathSignal int func (p ParentDeathSignal) Restore() error { @@ -40,8 +54,16 @@ func Execv(cmd string, args []string, env []string) error { return syscall.Exec(name, args, env) } +func Prlimit(pid, resource int, limit unix.Rlimit) error { + _, _, err := unix.RawSyscall6(unix.SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(&limit)), uintptr(unsafe.Pointer(&limit)), 0, 0) + if err != 0 { + return err + } + return nil +} + func SetParentDeathSignal(sig uintptr) error { - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, sig, 0); err != 0 { + if err := unix.Prctl(unix.PR_SET_PDEATHSIG, sig, 0, 0, 0); err != nil { return err } return nil @@ -49,15 +71,14 @@ func SetParentDeathSignal(sig uintptr) error { func GetParentDeathSignal() (ParentDeathSignal, error) { var sig int - _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_PDEATHSIG, uintptr(unsafe.Pointer(&sig)), 0) - if err != 0 { + if err := unix.Prctl(unix.PR_GET_PDEATHSIG, uintptr(unsafe.Pointer(&sig)), 0, 0, 0); err != nil { return -1, err } return ParentDeathSignal(sig), nil } func SetKeepCaps() error { - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 1, 0); err != 0 { + if err := unix.Prctl(unix.PR_SET_KEEPCAPS, 1, 0, 0, 0); err != nil { return err } @@ -65,7 +86,7 @@ func SetKeepCaps() error { } func ClearKeepCaps() error { - if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 0, 0); err != 0 { + if err := unix.Prctl(unix.PR_SET_KEEPCAPS, 0, 0, 0, 0); err != nil { return err } @@ -73,50 +94,62 @@ func ClearKeepCaps() error { } func Setctty() error { - if _, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0); err != 0 { + if err := unix.IoctlSetInt(0, unix.TIOCSCTTY, 0); err != nil { return err } return nil } -/* - * Detect whether we are currently running in a user namespace. - * Copied from github.com/lxc/lxd/shared/util.go - */ +// RunningInUserNS detects whether we are currently running in a user namespace. +// Originally copied from github.com/lxc/lxd/shared/util.go func RunningInUserNS() bool { - file, err := os.Open("/proc/self/uid_map") - if err != nil { - /* - * This kernel-provided file only exists if user namespaces are - * supported - */ - return false - } - defer file.Close() - - buf := bufio.NewReader(file) - l, _, err := buf.ReadLine() + uidmap, err := user.CurrentProcessUIDMap() if err != nil { + // This kernel-provided file only exists if user namespaces are supported return false } + return UIDMapInUserNS(uidmap) +} - line := string(l) - var a, b, c int64 - fmt.Sscanf(line, "%d %d %d", &a, &b, &c) +func UIDMapInUserNS(uidmap []user.IDMap) bool { /* * We assume we are in the initial user namespace if we have a full * range - 4294967295 uids starting at uid 0. */ - if a == 0 && b == 0 && c == 4294967295 { + if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 { return false } return true } -func Prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { - _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) - if e1 != 0 { - err = e1 +// GetParentNSeuid returns the euid within the parent user namespace +func GetParentNSeuid() int64 { + euid := int64(os.Geteuid()) + uidmap, err := user.CurrentProcessUIDMap() + if err != nil { + // This kernel-provided file only exists if user namespaces are supported + return euid + } + for _, um := range uidmap { + if um.ID <= euid && euid <= um.ID+um.Count-1 { + return um.ParentID + euid - um.ID + } + } + return euid +} + +// SetSubreaper sets the value i as the subreaper setting for the calling process +func SetSubreaper(i int) error { + return unix.Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) +} + +// GetSubreaper returns the subreaper setting for the calling process +func GetSubreaper() (int, error) { + var i uintptr + + if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil { + return -1, err } - return + + return int(i), nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux_test.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux_test.go new file mode 100644 index 0000000000000000000000000000000000000000..4d613d8473da8ea4e6330691d7f2472f5b220279 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux_test.go @@ -0,0 +1,45 @@ +// +build linux + +package system + +import ( + "strings" + "testing" + + "github.com/opencontainers/runc/libcontainer/user" +) + +func TestUIDMapInUserNS(t *testing.T) { + cases := []struct { + s string + expected bool + }{ + { + s: " 0 0 4294967295\n", + expected: false, + }, + { + s: " 0 0 1\n", + expected: true, + }, + { + s: " 0 1001 1\n 1 231072 65536\n", + expected: true, + }, + { + // file exist but empty (the initial state when userns is created. see man 7 user_namespaces) + s: "", + expected: true, + }, + } + for _, c := range cases { + uidmap, err := user.ParseIDMap(strings.NewReader(c.s)) + if err != nil { + t.Fatal(err) + } + actual := UIDMapInUserNS(uidmap) + if c.expected != actual { + t.Fatalf("expected %v, got %v for %q", c.expected, actual, c.s) + } + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go b/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go index 37808a29f6adbe8d5b84e79c06f2eef0066b86ac..79232a43715b2d42c895ee421707c798d14c430e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/proc.go @@ -1,27 +1,113 @@ package system import ( + "fmt" "io/ioutil" "path/filepath" "strconv" "strings" ) -// look in /proc to find the process start time so that we can verify -// that this pid has started after ourself +// State is the status of a process. +type State rune + +const ( // Only values for Linux 3.14 and later are listed here + Dead State = 'X' + DiskSleep State = 'D' + Running State = 'R' + Sleeping State = 'S' + Stopped State = 'T' + TracingStop State = 't' + Zombie State = 'Z' +) + +// String forms of the state from proc(5)'s documentation for +// /proc/[pid]/status' "State" field. +func (s State) String() string { + switch s { + case Dead: + return "dead" + case DiskSleep: + return "disk sleep" + case Running: + return "running" + case Sleeping: + return "sleeping" + case Stopped: + return "stopped" + case TracingStop: + return "tracing stop" + case Zombie: + return "zombie" + default: + return fmt.Sprintf("unknown (%c)", s) + } +} + +// Stat_t represents the information from /proc/[pid]/stat, as +// described in proc(5) with names based on the /proc/[pid]/status +// fields. +type Stat_t struct { + // PID is the process ID. + PID uint + + // Name is the command run by the process. + Name string + + // State is the state of the process. + State State + + // StartTime is the number of clock ticks after system boot (since + // Linux 2.6). + StartTime uint64 +} + +// Stat returns a Stat_t instance for the specified process. +func Stat(pid int) (stat Stat_t, err error) { + bytes, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) + if err != nil { + return stat, err + } + return parseStat(string(bytes)) +} + +// GetProcessStartTime is deprecated. Use Stat(pid) and +// Stat_t.StartTime instead. func GetProcessStartTime(pid int) (string, error) { - data, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) + stat, err := Stat(pid) if err != nil { return "", err } + return fmt.Sprintf("%d", stat.StartTime), nil +} + +func parseStat(data string) (stat Stat_t, err error) { + // From proc(5), field 2 could contain space and is inside `(` and `)`. + // The following is an example: + // 89653 (gunicorn: maste) S 89630 89653 89653 0 -1 4194560 29689 28896 0 3 146 32 76 19 20 0 1 0 2971844 52965376 3920 18446744073709551615 1 1 0 0 0 0 0 16781312 137447943 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 + i := strings.LastIndex(data, ")") + if i <= 2 || i >= len(data)-1 { + return stat, fmt.Errorf("invalid stat data: %q", data) + } + + parts := strings.SplitN(data[:i], "(", 2) + if len(parts) != 2 { + return stat, fmt.Errorf("invalid stat data: %q", data) + } + + stat.Name = parts[1] + _, err = fmt.Sscanf(parts[0], "%d", &stat.PID) + if err != nil { + return stat, err + } - parts := strings.Split(string(data), " ") - // the starttime is located at pos 22 - // from the man page - // - // starttime %llu (was %lu before Linux 2.6) - // (22) The time the process started after system boot. In kernels before Linux 2.6, this - // value was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks - // (divide by sysconf(_SC_CLK_TCK)). - return parts[22-1], nil // starts at 1 + // parts indexes should be offset by 3 from the field number given + // proc(5), because parts is zero-indexed and we've removed fields + // one (PID) and two (Name) in the paren-split. + parts = strings.Split(data[i+2:], " ") + var state int + fmt.Sscanf(parts[3-3], "%c", &state) + stat.State = State(state) + fmt.Sscanf(parts[22-3], "%d", &stat.StartTime) + return stat, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/proc_test.go b/vendor/github.com/opencontainers/runc/libcontainer/system/proc_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7e1acc5bcb45b4f42ead7a7c4732e5f1281c9e7d --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/proc_test.go @@ -0,0 +1,45 @@ +package system + +import "testing" + +func TestParseStartTime(t *testing.T) { + data := map[string]Stat_t{ + "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": { + PID: 4902, + Name: "gunicorn: maste", + State: 'S', + StartTime: 9126532, + }, + "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": { + PID: 9534, + Name: "cat", + State: 'R', + StartTime: 9214966, + }, + + "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": { + PID: 24767, + Name: "irq/44-mei_me", + State: 'S', + StartTime: 8722075, + }, + } + for line, expected := range data { + st, err := parseStat(line) + if err != nil { + t.Fatal(err) + } + if st.PID != expected.PID { + t.Fatalf("expected PID %q but received %q", expected.PID, st.PID) + } + if st.State != expected.State { + t.Fatalf("expected state %q but received %q", expected.State, st.State) + } + if st.Name != expected.Name { + t.Fatalf("expected name %q but received %q", expected.Name, st.Name) + } + if st.StartTime != expected.StartTime { + t.Fatalf("expected start time %q but received %q", expected.StartTime, st.StartTime) + } + } +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/setns_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/setns_linux.go deleted file mode 100644 index 615ff4c82742d01be896af2e8dfde6d1d8d59fce..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/setns_linux.go +++ /dev/null @@ -1,40 +0,0 @@ -package system - -import ( - "fmt" - "runtime" - "syscall" -) - -// Via http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=7b21fddd087678a70ad64afc0f632e0f1071b092 -// -// We need different setns values for the different platforms and arch -// We are declaring the macro here because the SETNS syscall does not exist in th stdlib -var setNsMap = map[string]uintptr{ - "linux/386": 346, - "linux/arm64": 268, - "linux/amd64": 308, - "linux/arm": 375, - "linux/ppc": 350, - "linux/ppc64": 350, - "linux/ppc64le": 350, - "linux/s390x": 339, -} - -var sysSetns = setNsMap[fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)] - -func SysSetns() uint32 { - return uint32(sysSetns) -} - -func Setns(fd uintptr, flags uintptr) error { - ns, exists := setNsMap[fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)] - if !exists { - return fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH) - } - _, _, err := syscall.RawSyscall(ns, fd, flags, 0) - if err != 0 { - return err - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_386.go b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go similarity index 61% rename from vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_386.go rename to vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go index c99006518907cf732991111230ff54a12bec797a..c5ca5d86235b94180fb4f55dcbe8285e07505142 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_386.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_32.go @@ -1,14 +1,15 @@ -// +build linux,386 +// +build linux +// +build 386 arm package system import ( - "syscall" + "golang.org/x/sys/unix" ) // Setuid sets the uid of the calling thread to the specified uid. func Setuid(uid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := unix.RawSyscall(unix.SYS_SETUID32, uintptr(uid), 0, 0) if e1 != 0 { err = e1 } @@ -17,7 +18,7 @@ func Setuid(uid int) (err error) { // Setgid sets the gid of the calling thread to the specified gid. func Setgid(gid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID32, uintptr(gid), 0, 0) + _, _, e1 := unix.RawSyscall(unix.SYS_SETGID32, uintptr(gid), 0, 0) if e1 != 0 { err = e1 } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go index 0816bf8281698f4202c28cfeea7293d3252569b0..11c3faafbf0bd29f65afa1cfe7b66e7558c9e7a2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go @@ -1,14 +1,15 @@ -// +build linux,arm64 linux,amd64 linux,ppc linux,ppc64 linux,ppc64le linux,s390x +// +build linux +// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le s390x package system import ( - "syscall" + "golang.org/x/sys/unix" ) // Setuid sets the uid of the calling thread to the specified uid. func Setuid(uid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0) + _, _, e1 := unix.RawSyscall(unix.SYS_SETUID, uintptr(uid), 0, 0) if e1 != 0 { err = e1 } @@ -17,7 +18,7 @@ func Setuid(uid int) (err error) { // Setgid sets the gid of the calling thread to the specified gid. func Setgid(gid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID, uintptr(gid), 0, 0) + _, _, e1 := unix.RawSyscall(unix.SYS_SETGID, uintptr(gid), 0, 0) if e1 != 0 { err = e1 } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_arm.go b/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_arm.go deleted file mode 100644 index 3f780f312bd575f98329fd5447872c100bc55333..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_arm.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build linux,arm - -package system - -import ( - "syscall" -) - -// Setuid sets the uid of the calling thread to the specified uid. -func Setuid(uid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETUID32, uintptr(uid), 0, 0) - if e1 != 0 { - err = e1 - } - return -} - -// Setgid sets the gid of the calling thread to the specified gid. -func Setgid(gid int) (err error) { - _, _, e1 := syscall.RawSyscall(syscall.SYS_SETGID32, uintptr(gid), 0, 0) - if e1 != 0 { - err = e1 - } - return -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go b/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go index b3a07cba3efa1dc0aa1f8ec95237874f2516a68f..b8434f10500b3c6301d6da9be0353d2ad8921dda 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go @@ -1,4 +1,4 @@ -// +build cgo,linux cgo,freebsd +// +build cgo,linux package system diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/system/unsupported.go index e7cfd62b293c4dff41f626e4a1cf82bcb4dc1a27..b94be74a6648bbec4819744a7fd3366b48acec87 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/unsupported.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/unsupported.go @@ -2,8 +2,26 @@ package system +import ( + "os" + + "github.com/opencontainers/runc/libcontainer/user" +) + // RunningInUserNS is a stub for non-Linux systems // Always returns false func RunningInUserNS() bool { return false } + +// UIDMapInUserNS is a stub for non-Linux systems +// Always returns false +func UIDMapInUserNS(uidmap []user.IDMap) bool { + return false +} + +// GetParentNSeuid returns the euid within the parent user namespace +// Always returns os.Geteuid on non-linux +func GetParentNSeuid() int { + return os.Geteuid() +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go index 30f74dfb1b4aebc396adc2c39eb7160ebd85e77f..a6823fc99b2c83d08d3b8ba51bab6c66f79c41f7 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/xattrs_linux.go @@ -1,99 +1,35 @@ package system -import ( - "syscall" - "unsafe" -) - -var _zero uintptr - -// Returns the size of xattrs and nil error -// Requires path, takes allocated []byte or nil as last argument -func Llistxattr(path string, dest []byte) (size int, err error) { - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return -1, err - } - var newpathBytes unsafe.Pointer - if len(dest) > 0 { - newpathBytes = unsafe.Pointer(&dest[0]) - } else { - newpathBytes = unsafe.Pointer(&_zero) - } - - _size, _, errno := syscall.Syscall6(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(newpathBytes), uintptr(len(dest)), 0, 0, 0) - size = int(_size) - if errno != 0 { - return -1, errno - } - - return size, nil -} +import "golang.org/x/sys/unix" // Returns a []byte slice if the xattr is set and nil otherwise // Requires path and its attribute as arguments func Lgetxattr(path string, attr string) ([]byte, error) { var sz int - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return nil, err - } - // Start with a 128 length byte array - sz = 128 - dest := make([]byte, sz) - destBytes := unsafe.Pointer(&dest[0]) - _sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + dest := make([]byte, 128) + sz, errno := unix.Lgetxattr(path, attr, dest) switch { - case errno == syscall.ENODATA: + case errno == unix.ENODATA: return nil, errno - case errno == syscall.ENOTSUP: + case errno == unix.ENOTSUP: return nil, errno - case errno == syscall.ERANGE: + case errno == unix.ERANGE: // 128 byte array might just not be good enough, - // A dummy buffer is used ``uintptr(0)`` to get real size + // A dummy buffer is used to get the real size // of the xattrs on disk - _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0) - sz = int(_sz) - if sz < 0 { + sz, errno = unix.Lgetxattr(path, attr, []byte{}) + if errno != nil { return nil, errno } dest = make([]byte, sz) - destBytes := unsafe.Pointer(&dest[0]) - _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - if errno != 0 { + sz, errno = unix.Lgetxattr(path, attr, dest) + if errno != nil { return nil, errno } - case errno != 0: + case errno != nil: return nil, errno } - sz = int(_sz) return dest[:sz], nil } - -func Lsetxattr(path string, attr string, data []byte, flags int) error { - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return err - } - var dataBytes unsafe.Pointer - if len(data) > 0 { - dataBytes = unsafe.Pointer(&data[0]) - } else { - dataBytes = unsafe.Pointer(&_zero) - } - _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) - if errno != 0 { - return errno - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go index 6f8a982ff72a697e61f800ce2e36f281e65ff8c4..6fd8dd0d44aa55aeeef76948d45b599e5aaa45ff 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup.go @@ -2,107 +2,40 @@ package user import ( "errors" - "fmt" - "syscall" ) var ( // The current operating system does not provide the required data for user lookups. ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data") + // No matching entries found in file. + ErrNoPasswdEntries = errors.New("no matching entries in passwd file") + ErrNoGroupEntries = errors.New("no matching entries in group file") ) -func lookupUser(filter func(u User) bool) (User, error) { - // Get operating system-specific passwd reader-closer. - passwd, err := GetPasswd() - if err != nil { - return User{}, err - } - defer passwd.Close() - - // Get the users. - users, err := ParsePasswdFilter(passwd, filter) - if err != nil { - return User{}, err - } - - // No user entries found. - if len(users) == 0 { - return User{}, fmt.Errorf("no matching entries in passwd file") - } - - // Assume the first entry is the "correct" one. - return users[0], nil -} - -// CurrentUser looks up the current user by their user id in /etc/passwd. If the -// user cannot be found (or there is no /etc/passwd file on the filesystem), -// then CurrentUser returns an error. -func CurrentUser() (User, error) { - return LookupUid(syscall.Getuid()) -} - // LookupUser looks up a user by their username in /etc/passwd. If the user // cannot be found (or there is no /etc/passwd file on the filesystem), then // LookupUser returns an error. func LookupUser(username string) (User, error) { - return lookupUser(func(u User) bool { - return u.Name == username - }) + return lookupUser(username) } // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot // be found (or there is no /etc/passwd file on the filesystem), then LookupId // returns an error. func LookupUid(uid int) (User, error) { - return lookupUser(func(u User) bool { - return u.Uid == uid - }) -} - -func lookupGroup(filter func(g Group) bool) (Group, error) { - // Get operating system-specific group reader-closer. - group, err := GetGroup() - if err != nil { - return Group{}, err - } - defer group.Close() - - // Get the users. - groups, err := ParseGroupFilter(group, filter) - if err != nil { - return Group{}, err - } - - // No user entries found. - if len(groups) == 0 { - return Group{}, fmt.Errorf("no matching entries in group file") - } - - // Assume the first entry is the "correct" one. - return groups[0], nil -} - -// CurrentGroup looks up the current user's group by their primary group id's -// entry in /etc/passwd. If the group cannot be found (or there is no -// /etc/group file on the filesystem), then CurrentGroup returns an error. -func CurrentGroup() (Group, error) { - return LookupGid(syscall.Getgid()) + return lookupUid(uid) } // LookupGroup looks up a group by its name in /etc/group. If the group cannot // be found (or there is no /etc/group file on the filesystem), then LookupGroup // returns an error. func LookupGroup(groupname string) (Group, error) { - return lookupGroup(func(g Group) bool { - return g.Name == groupname - }) + return lookupGroup(groupname) } // LookupGid looks up a group by its group id in /etc/group. If the group cannot // be found (or there is no /etc/group file on the filesystem), then LookupGid // returns an error. func LookupGid(gid int) (Group, error) { - return lookupGroup(func(g Group) bool { - return g.Gid == gid - }) + return lookupGid(gid) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go index 758b734c225abc5b068fe94356cc2129be88fe16..92b5ae8de0177f6001fff3a8e840be3837a3d6ef 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go @@ -5,6 +5,9 @@ package user import ( "io" "os" + "strconv" + + "golang.org/x/sys/unix" ) // Unix-specific path to the passwd and group formatted files. @@ -13,6 +16,76 @@ const ( unixGroupPath = "/etc/group" ) +func lookupUser(username string) (User, error) { + return lookupUserFunc(func(u User) bool { + return u.Name == username + }) +} + +func lookupUid(uid int) (User, error) { + return lookupUserFunc(func(u User) bool { + return u.Uid == uid + }) +} + +func lookupUserFunc(filter func(u User) bool) (User, error) { + // Get operating system-specific passwd reader-closer. + passwd, err := GetPasswd() + if err != nil { + return User{}, err + } + defer passwd.Close() + + // Get the users. + users, err := ParsePasswdFilter(passwd, filter) + if err != nil { + return User{}, err + } + + // No user entries found. + if len(users) == 0 { + return User{}, ErrNoPasswdEntries + } + + // Assume the first entry is the "correct" one. + return users[0], nil +} + +func lookupGroup(groupname string) (Group, error) { + return lookupGroupFunc(func(g Group) bool { + return g.Name == groupname + }) +} + +func lookupGid(gid int) (Group, error) { + return lookupGroupFunc(func(g Group) bool { + return g.Gid == gid + }) +} + +func lookupGroupFunc(filter func(g Group) bool) (Group, error) { + // Get operating system-specific group reader-closer. + group, err := GetGroup() + if err != nil { + return Group{}, err + } + defer group.Close() + + // Get the users. + groups, err := ParseGroupFilter(group, filter) + if err != nil { + return Group{}, err + } + + // No user entries found. + if len(groups) == 0 { + return Group{}, ErrNoGroupEntries + } + + // Assume the first entry is the "correct" one. + return groups[0], nil +} + func GetPasswdPath() (string, error) { return unixPasswdPath, nil } @@ -28,3 +101,44 @@ func GetGroupPath() (string, error) { func GetGroup() (io.ReadCloser, error) { return os.Open(unixGroupPath) } + +// CurrentUser looks up the current user by their user id in /etc/passwd. If the +// user cannot be found (or there is no /etc/passwd file on the filesystem), +// then CurrentUser returns an error. +func CurrentUser() (User, error) { + return LookupUid(unix.Getuid()) +} + +// CurrentGroup looks up the current user's group by their primary group id's +// entry in /etc/passwd. If the group cannot be found (or there is no +// /etc/group file on the filesystem), then CurrentGroup returns an error. +func CurrentGroup() (Group, error) { + return LookupGid(unix.Getgid()) +} + +func currentUserSubIDs(fileName string) ([]SubID, error) { + u, err := CurrentUser() + if err != nil { + return nil, err + } + filter := func(entry SubID) bool { + return entry.Name == u.Name || entry.Name == strconv.Itoa(u.Uid) + } + return ParseSubIDFileFilter(fileName, filter) +} + +func CurrentUserSubUIDs() ([]SubID, error) { + return currentUserSubIDs("/etc/subuid") +} + +func CurrentUserSubGIDs() ([]SubID, error) { + return currentUserSubIDs("/etc/subgid") +} + +func CurrentProcessUIDMap() ([]IDMap, error) { + return ParseIDMapFile("/proc/self/uid_map") +} + +func CurrentProcessGIDMap() ([]IDMap, error) { + return ParseIDMapFile("/proc/self/gid_map") +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go deleted file mode 100644 index 7217948870c51d215eb7f1bc0bf4c01eeba76993..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris - -package user - -import "io" - -func GetPasswdPath() (string, error) { - return "", ErrUnsupported -} - -func GetPasswd() (io.ReadCloser, error) { - return nil, ErrUnsupported -} - -func GetGroupPath() (string, error) { - return "", ErrUnsupported -} - -func GetGroup() (io.ReadCloser, error) { - return nil, ErrUnsupported -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_windows.go new file mode 100644 index 0000000000000000000000000000000000000000..65cd40e9287b99d56df3a246128b72c1b8bc9e4c --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_windows.go @@ -0,0 +1,40 @@ +// +build windows + +package user + +import ( + "fmt" + "os/user" +) + +func lookupUser(username string) (User, error) { + u, err := user.Lookup(username) + if err != nil { + return User{}, err + } + return userFromOS(u) +} + +func lookupUid(uid int) (User, error) { + u, err := user.LookupId(fmt.Sprintf("%d", uid)) + if err != nil { + return User{}, err + } + return userFromOS(u) +} + +func lookupGroup(groupname string) (Group, error) { + g, err := user.LookupGroup(groupname) + if err != nil { + return Group{}, err + } + return groupFromOS(g) +} + +func lookupGid(gid int) (Group, error) { + g, err := user.LookupGroupId(fmt.Sprintf("%d", gid)) + if err != nil { + return Group{}, err + } + return groupFromOS(g) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go index e6375ea4dd53ffd7423f8fa7693801024ae8b063..7b912bbf8b44fef879ac7b47c0d6a03e00ee1224 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "os/user" "strconv" "strings" ) @@ -15,7 +16,7 @@ const ( ) var ( - ErrRange = fmt.Errorf("Uids and gids must be in range %d-%d", minId, maxId) + ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minId, maxId) ) type User struct { @@ -28,6 +29,28 @@ type User struct { Shell string } +// userFromOS converts an os/user.(*User) to local User +// +// (This does not include Pass, Shell or Gecos) +func userFromOS(u *user.User) (User, error) { + newUser := User{ + Name: u.Username, + Home: u.HomeDir, + } + id, err := strconv.Atoi(u.Uid) + if err != nil { + return newUser, err + } + newUser.Uid = id + + id, err = strconv.Atoi(u.Gid) + if err != nil { + return newUser, err + } + newUser.Gid = id + return newUser, nil +} + type Group struct { Name string Pass string @@ -35,36 +58,73 @@ type Group struct { List []string } +// groupFromOS converts an os/user.(*Group) to local Group +// +// (This does not include Pass, Shell or Gecos) +func groupFromOS(g *user.Group) (Group, error) { + newGroup := Group{ + Name: g.Name, + } + + id, err := strconv.Atoi(g.Gid) + if err != nil { + return newGroup, err + } + newGroup.Gid = id + + return newGroup, nil +} + +// SubID represents an entry in /etc/sub{u,g}id +type SubID struct { + Name string + SubID int64 + Count int64 +} + +// IDMap represents an entry in /proc/PID/{u,g}id_map +type IDMap struct { + ID int64 + ParentID int64 + Count int64 +} + func parseLine(line string, v ...interface{}) { - if line == "" { + parseParts(strings.Split(line, ":"), v...) +} + +func parseParts(parts []string, v ...interface{}) { + if len(parts) == 0 { return } - parts := strings.Split(line, ":") for i, p := range parts { + // Ignore cases where we don't have enough fields to populate the arguments. + // Some configuration files like to misbehave. if len(v) <= i { - // if we have more "parts" than we have places to put them, bail for great "tolerance" of naughty configuration files break } + // Use the type of the argument to figure out how to parse it, scanf() style. + // This is legit. switch e := v[i].(type) { case *string: - // "root", "adm", "/bin/bash" *e = p case *int: - // "0", "4", "1000" - // ignore string to int conversion errors, for great "tolerance" of naughty configuration files + // "numbers", with conversion errors ignored because of some misbehaving configuration files. *e, _ = strconv.Atoi(p) + case *int64: + *e, _ = strconv.ParseInt(p, 10, 64) case *[]string: - // "", "root", "root,adm,daemon" + // Comma-separated lists. if p != "" { *e = strings.Split(p, ",") } else { *e = []string{} } default: - // panic, because this is a programming/logic error, not a runtime one - panic("parseLine expects only pointers! argument " + strconv.Itoa(i) + " is not a pointer!") + // Someone goof'd when writing code using this function. Scream so they can hear us. + panic(fmt.Sprintf("parseLine only accepts {*string, *int, *int64, *[]string} as arguments! %#v is not a pointer!", e)) } } } @@ -106,8 +166,8 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { return nil, err } - text := strings.TrimSpace(s.Text()) - if text == "" { + line := strings.TrimSpace(s.Text()) + if line == "" { continue } @@ -117,10 +177,7 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { // root:x:0:0:root:/root:/bin/bash // adm:x:3:4:adm:/var/adm:/bin/false p := User{} - parseLine( - text, - &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell, - ) + parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell) if filter == nil || filter(p) { out = append(out, p) @@ -135,6 +192,7 @@ func ParseGroupFile(path string) ([]Group, error) { if err != nil { return nil, err } + defer group.Close() return ParseGroup(group) } @@ -178,10 +236,7 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { // root:x:0:root // adm:x:4:root,adm,daemon p := Group{} - parseLine( - text, - &p.Name, &p.Pass, &p.Gid, &p.List, - ) + parseLine(text, &p.Name, &p.Pass, &p.Gid, &p.List) if filter == nil || filter(p) { out = append(out, p) @@ -192,9 +247,10 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { } type ExecUser struct { - Uid, Gid int - Sgids []int - Home string + Uid int + Gid int + Sgids []int + Home string } // GetExecUserPath is a wrapper for GetExecUser. It reads data from each of the @@ -202,18 +258,16 @@ type ExecUser struct { // files cannot be opened for any reason, the error is ignored and a nil // io.Reader is passed instead. func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) { - passwd, err := os.Open(passwdPath) - if err != nil { - passwd = nil - } else { - defer passwd.Close() + var passwd, group io.Reader + + if passwdFile, err := os.Open(passwdPath); err == nil { + passwd = passwdFile + defer passwdFile.Close() } - group, err := os.Open(groupPath) - if err != nil { - group = nil - } else { - defer group.Close() + if groupFile, err := os.Open(groupPath); err == nil { + group = groupFile + defer groupFile.Close() } return GetExecUser(userSpec, defaults, passwd, group) @@ -235,12 +289,12 @@ func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath // * "uid:gid // * "user:gid" // * "uid:group" +// +// It should be noted that if you specify a numeric user or group id, they will +// not be evaluated as usernames (only the metadata will be filled). So attempting +// to parse a user with user.Name = "1337" will produce the user with a UID of +// 1337. func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (*ExecUser, error) { - var ( - userArg, groupArg string - name string - ) - if defaults == nil { defaults = new(ExecUser) } @@ -258,87 +312,113 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( user.Sgids = []int{} } - // allow for userArg to have either "user" syntax, or optionally "user:group" syntax + // Allow for userArg to have either "user" syntax, or optionally "user:group" syntax + var userArg, groupArg string parseLine(userSpec, &userArg, &groupArg) + // Convert userArg and groupArg to be numeric, so we don't have to execute + // Atoi *twice* for each iteration over lines. + uidArg, uidErr := strconv.Atoi(userArg) + gidArg, gidErr := strconv.Atoi(groupArg) + + // Find the matching user. users, err := ParsePasswdFilter(passwd, func(u User) bool { if userArg == "" { + // Default to current state of the user. return u.Uid == user.Uid } - return u.Name == userArg || strconv.Itoa(u.Uid) == userArg + + if uidErr == nil { + // If the userArg is numeric, always treat it as a UID. + return uidArg == u.Uid + } + + return u.Name == userArg }) + + // If we can't find the user, we have to bail. if err != nil && passwd != nil { if userArg == "" { userArg = strconv.Itoa(user.Uid) } - return nil, fmt.Errorf("Unable to find user %v: %v", userArg, err) + return nil, fmt.Errorf("unable to find user %s: %v", userArg, err) } - haveUser := users != nil && len(users) > 0 - if haveUser { - // if we found any user entries that matched our filter, let's take the first one as "correct" - name = users[0].Name + var matchedUserName string + if len(users) > 0 { + // First match wins, even if there's more than one matching entry. + matchedUserName = users[0].Name user.Uid = users[0].Uid user.Gid = users[0].Gid user.Home = users[0].Home } else if userArg != "" { - // we asked for a user but didn't find them... let's check to see if we wanted a numeric user - user.Uid, err = strconv.Atoi(userArg) - if err != nil { - // not numeric - we have to bail - return nil, fmt.Errorf("Unable to find user %v", userArg) + // If we can't find a user with the given username, the only other valid + // option is if it's a numeric username with no associated entry in passwd. + + if uidErr != nil { + // Not numeric. + return nil, fmt.Errorf("unable to find user %s: %v", userArg, ErrNoPasswdEntries) } + user.Uid = uidArg // Must be inside valid uid range. if user.Uid < minId || user.Uid > maxId { return nil, ErrRange } - // if userArg couldn't be found in /etc/passwd but is numeric, just roll with it - this is legit + // Okay, so it's numeric. We can just roll with this. } - if groupArg != "" || name != "" { + // On to the groups. If we matched a username, we need to do this because of + // the supplementary group IDs. + if groupArg != "" || matchedUserName != "" { groups, err := ParseGroupFilter(group, func(g Group) bool { - // Explicit group format takes precedence. - if groupArg != "" { - return g.Name == groupArg || strconv.Itoa(g.Gid) == groupArg + // If the group argument isn't explicit, we'll just search for it. + if groupArg == "" { + // Check if user is a member of this group. + for _, u := range g.List { + if u == matchedUserName { + return true + } + } + return false } - // Check if user is a member. - for _, u := range g.List { - if u == name { - return true - } + if gidErr == nil { + // If the groupArg is numeric, always treat it as a GID. + return gidArg == g.Gid } - return false + return g.Name == groupArg }) if err != nil && group != nil { - return nil, fmt.Errorf("Unable to find groups for user %v: %v", users[0].Name, err) + return nil, fmt.Errorf("unable to find groups for spec %v: %v", matchedUserName, err) } - haveGroup := groups != nil && len(groups) > 0 + // Only start modifying user.Gid if it is in explicit form. if groupArg != "" { - if haveGroup { - // if we found any group entries that matched our filter, let's take the first one as "correct" + if len(groups) > 0 { + // First match wins, even if there's more than one matching entry. user.Gid = groups[0].Gid } else { - // we asked for a group but didn't find id... let's check to see if we wanted a numeric group - user.Gid, err = strconv.Atoi(groupArg) - if err != nil { - // not numeric - we have to bail - return nil, fmt.Errorf("Unable to find group %v", groupArg) + // If we can't find a group with the given name, the only other valid + // option is if it's a numeric group name with no associated entry in group. + + if gidErr != nil { + // Not numeric. + return nil, fmt.Errorf("unable to find group %s: %v", groupArg, ErrNoGroupEntries) } + user.Gid = gidArg - // Ensure gid is inside gid range. + // Must be inside valid gid range. if user.Gid < minId || user.Gid > maxId { return nil, ErrRange } - // if groupArg couldn't be found in /etc/group but is numeric, just roll with it - this is legit + // Okay, so it's numeric. We can just roll with this. } - } else if haveGroup { - // If implicit group format, fill supplementary gids. + } else if len(groups) > 0 { + // Supplementary group ids only make sense if in the implicit form. user.Sgids = make([]int, len(groups)) for i, group := range groups { user.Sgids[i] = group.Gid @@ -410,9 +490,119 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err // that opens the groupPath given and gives it as an argument to // GetAdditionalGroups. func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) { - group, err := os.Open(groupPath) - if err == nil { - defer group.Close() + var group io.Reader + + if groupFile, err := os.Open(groupPath); err == nil { + group = groupFile + defer groupFile.Close() } return GetAdditionalGroups(additionalGroups, group) } + +func ParseSubIDFile(path string) ([]SubID, error) { + subid, err := os.Open(path) + if err != nil { + return nil, err + } + defer subid.Close() + return ParseSubID(subid) +} + +func ParseSubID(subid io.Reader) ([]SubID, error) { + return ParseSubIDFilter(subid, nil) +} + +func ParseSubIDFileFilter(path string, filter func(SubID) bool) ([]SubID, error) { + subid, err := os.Open(path) + if err != nil { + return nil, err + } + defer subid.Close() + return ParseSubIDFilter(subid, filter) +} + +func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) { + if r == nil { + return nil, fmt.Errorf("nil source for subid-formatted data") + } + + var ( + s = bufio.NewScanner(r) + out = []SubID{} + ) + + for s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + + line := strings.TrimSpace(s.Text()) + if line == "" { + continue + } + + // see: man 5 subuid + p := SubID{} + parseLine(line, &p.Name, &p.SubID, &p.Count) + + if filter == nil || filter(p) { + out = append(out, p) + } + } + + return out, nil +} + +func ParseIDMapFile(path string) ([]IDMap, error) { + r, err := os.Open(path) + if err != nil { + return nil, err + } + defer r.Close() + return ParseIDMap(r) +} + +func ParseIDMap(r io.Reader) ([]IDMap, error) { + return ParseIDMapFilter(r, nil) +} + +func ParseIDMapFileFilter(path string, filter func(IDMap) bool) ([]IDMap, error) { + r, err := os.Open(path) + if err != nil { + return nil, err + } + defer r.Close() + return ParseIDMapFilter(r, filter) +} + +func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) { + if r == nil { + return nil, fmt.Errorf("nil source for idmap-formatted data") + } + + var ( + s = bufio.NewScanner(r) + out = []IDMap{} + ) + + for s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + + line := strings.TrimSpace(s.Text()) + if line == "" { + continue + } + + // see: man 7 user_namespaces + p := IDMap{} + parseParts(strings.Fields(line), &p.ID, &p.ParentID, &p.Count) + + if filter == nil || filter(p) { + out = append(out, p) + } + } + + return out, nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user_test.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user_test.go index 53b2289bf039c735a3d991806aebe97dd3435ff6..24ee559e13a48a5dc21490e308eab593d07593b0 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user_test.go @@ -7,6 +7,8 @@ import ( "strconv" "strings" "testing" + + "github.com/opencontainers/runc/libcontainer/utils" ) func TestUserParseLine(t *testing.T) { @@ -101,12 +103,16 @@ func TestValidGetExecUser(t *testing.T) { const passwdContent = ` root:x:0:0:root user:/root:/bin/bash adm:x:42:43:adm:/var/adm:/bin/false +111:x:222:333::/var/garbage +odd:x:111:112::/home/odd::::: this is just some garbage data ` const groupContent = ` root:x:0:root adm:x:43: grp:x:1234:root,adm +444:x:555:111 +odd:x:444: this is just some garbage data ` defaultExecUser := ExecUser{ @@ -192,6 +198,26 @@ this is just some garbage data Home: defaultExecUser.Home, }, }, + + // Regression tests for #695. + { + ref: "111", + expected: ExecUser{ + Uid: 111, + Gid: 112, + Sgids: defaultExecUser.Sgids, + Home: "/home/odd", + }, + }, + { + ref: "111:444", + expected: ExecUser{ + Uid: 111, + Gid: 444, + Sgids: defaultExecUser.Sgids, + Home: "/home/odd", + }, + }, } for _, test := range tests { @@ -206,6 +232,7 @@ this is just some garbage data } if !reflect.DeepEqual(test.expected, *execUser) { + t.Logf("ref: %v", test.ref) t.Logf("got: %#v", execUser) t.Logf("expected: %#v", test.expected) t.Fail() @@ -218,6 +245,7 @@ func TestInvalidGetExecUser(t *testing.T) { const passwdContent = ` root:x:0:0:root user:/root:/bin/bash adm:x:42:43:adm:/var/adm:/bin/false +-42:x:12:13:broken:/very/broken this is just some garbage data ` const groupContent = ` @@ -240,6 +268,8 @@ this is just some garbage data "-1:0", "0:-3", "-5:-2", + "-42", + "-43", } for _, test := range tests { @@ -354,6 +384,12 @@ this is just some garbage data } func TestGetAdditionalGroups(t *testing.T) { + type foo struct { + groups []string + expected []int + hasError bool + } + const groupContent = ` root:x:0:root adm:x:43: @@ -361,11 +397,7 @@ grp:x:1234:root,adm adm:x:4343:root,adm-duplicate this is just some garbage data ` - tests := []struct { - groups []string - expected []int - hasError bool - }{ + tests := []foo{ { // empty group groups: []string{}, @@ -408,12 +440,15 @@ this is just some garbage data expected: nil, hasError: true, }, - { + } + + if utils.GetIntSize() > 4 { + tests = append(tests, foo{ // groups with too large id groups: []string{strconv.Itoa(1 << 31)}, expected: nil, hasError: true, - }, + }) } for _, test := range tests { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go new file mode 100644 index 0000000000000000000000000000000000000000..c8a9364d54d776c37e226c17bb111a04aa85c048 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go @@ -0,0 +1,93 @@ +// +build linux + +package utils + +/* + * Copyright 2016, 2017 SUSE LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +// MaxSendfdLen is the maximum length of the name of a file descriptor being +// sent using SendFd. The name of the file handle returned by RecvFd will never +// be larger than this value. +const MaxNameLen = 4096 + +// oobSpace is the size of the oob slice required to store a single FD. Note +// that unix.UnixRights appears to make the assumption that fd is always int32, +// so sizeof(fd) = 4. +var oobSpace = unix.CmsgSpace(4) + +// RecvFd waits for a file descriptor to be sent over the given AF_UNIX +// socket. The file name of the remote file descriptor will be recreated +// locally (it is sent as non-auxiliary data in the same payload). +func RecvFd(socket *os.File) (*os.File, error) { + // For some reason, unix.Recvmsg uses the length rather than the capacity + // when passing the msg_controllen and other attributes to recvmsg. So we + // have to actually set the length. + name := make([]byte, MaxNameLen) + oob := make([]byte, oobSpace) + + sockfd := socket.Fd() + n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0) + if err != nil { + return nil, err + } + + if n >= MaxNameLen || oobn != oobSpace { + return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn) + } + + // Truncate. + name = name[:n] + oob = oob[:oobn] + + scms, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return nil, err + } + if len(scms) != 1 { + return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms)) + } + scm := scms[0] + + fds, err := unix.ParseUnixRights(&scm) + if err != nil { + return nil, err + } + if len(fds) != 1 { + return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds)) + } + fd := uintptr(fds[0]) + + return os.NewFile(fd, string(name)), nil +} + +// SendFd sends a file descriptor over the given AF_UNIX socket. In +// addition, the file.Name() of the given file will also be sent as +// non-auxiliary data in the same payload (allowing to send contextual +// information for a file descriptor). +func SendFd(socket *os.File, name string, fd uintptr) error { + if len(name) >= MaxNameLen { + return fmt.Errorf("sendfd: filename too long: %s", name) + } + oob := unix.UnixRights(int(fd)) + return unix.Sendmsg(int(socket.Fd()), []byte(name), oob, nil, 0) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go index 68ae3c477b4e7ecb5c025a85cd935be3c1d5f5a3..40ccfaa1a01aa660893382fe5474dec2275fabcc 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -1,32 +1,20 @@ package utils import ( - "crypto/rand" - "encoding/hex" "encoding/json" "io" "os" "path/filepath" - "syscall" + "strings" + "unsafe" + + "golang.org/x/sys/unix" ) const ( exitSignalOffset = 128 ) -// GenerateRandomName returns a new name joined with a prefix. This size -// specified is used to truncate the randomly generated value -func GenerateRandomName(prefix string, size int) (string, error) { - id := make([]byte, 32) - if _, err := io.ReadFull(rand.Reader, id); err != nil { - return "", err - } - if size > 64 { - size = 64 - } - return prefix + hex.EncodeToString(id)[:size], nil -} - // ResolveRootfs ensures that the current working directory is // not a symlink and returns the absolute path to the rootfs func ResolveRootfs(uncleanRootfs string) (string, error) { @@ -39,7 +27,7 @@ func ResolveRootfs(uncleanRootfs string) (string, error) { // ExitStatus returns the correct exit status for a process based on if it // was signaled or exited cleanly -func ExitStatus(status syscall.WaitStatus) int { +func ExitStatus(status unix.WaitStatus) int { if status.Signaled() { return exitSignalOffset + int(status.Signal()) } @@ -84,3 +72,41 @@ func CleanPath(path string) string { // Clean the path again for good measure. return filepath.Clean(path) } + +// SearchLabels searches a list of key-value pairs for the provided key and +// returns the corresponding value. The pairs must be separated with '='. +func SearchLabels(labels []string, query string) string { + for _, l := range labels { + parts := strings.SplitN(l, "=", 2) + if len(parts) < 2 { + continue + } + if parts[0] == query { + return parts[1] + } + } + return "" +} + +// Annotations returns the bundle path and user defined annotations from the +// libcontainer state. We need to remove the bundle because that is a label +// added by libcontainer. +func Annotations(labels []string) (bundle string, userAnnotations map[string]string) { + userAnnotations = make(map[string]string) + for _, l := range labels { + parts := strings.SplitN(l, "=", 2) + if len(parts) < 2 { + continue + } + if parts[0] == "bundle" { + bundle = parts[1] + } else { + userAnnotations[parts[0]] = parts[1] + } + } + return +} + +func GetIntSize() int { + return int(unsafe.Sizeof(1)) +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go index 813180a8a44bd5884bdbbd8860b6d1539ba47e8a..395eedcf66a322e0e23c9367e4fce055fe340f39 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_test.go @@ -1,25 +1,142 @@ package utils -import "testing" +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "testing" -func TestGenerateName(t *testing.T) { - name, err := GenerateRandomName("veth", 5) + "golang.org/x/sys/unix" +) + +var labelTest = []struct { + labels []string + query string + expectedValue string +}{ + {[]string{"bundle=/path/to/bundle"}, "bundle", "/path/to/bundle"}, + {[]string{"test=a", "test=b"}, "bundle", ""}, + {[]string{"bundle=a", "test=b", "bundle=c"}, "bundle", "a"}, + {[]string{"", "test=a", "bundle=b"}, "bundle", "b"}, + {[]string{"test", "bundle=a"}, "bundle", "a"}, + {[]string{"test=a", "bundle="}, "bundle", ""}, +} + +func TestSearchLabels(t *testing.T) { + for _, tt := range labelTest { + if v := SearchLabels(tt.labels, tt.query); v != tt.expectedValue { + t.Errorf("expected value '%s' for query '%s'; got '%s'", tt.expectedValue, tt.query, v) + } + } +} + +func TestResolveRootfs(t *testing.T) { + dir := "rootfs" + os.Mkdir(dir, 0600) + defer os.Remove(dir) + + path, err := ResolveRootfs(dir) if err != nil { t.Fatal(err) } + pwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + if path != fmt.Sprintf("%s/%s", pwd, "rootfs") { + t.Errorf("expected rootfs to be abs and was %s", path) + } +} + +func TestResolveRootfsWithSymlink(t *testing.T) { + dir := "rootfs" + tmpDir, _ := filepath.EvalSymlinks(os.TempDir()) + os.Symlink(tmpDir, dir) + defer os.Remove(dir) + + path, err := ResolveRootfs(dir) + if err != nil { + t.Fatal(err) + } + + if path != tmpDir { + t.Errorf("expected rootfs to be the real path %s and was %s", path, os.TempDir()) + } +} + +func TestResolveRootfsWithNonExistingDir(t *testing.T) { + _, err := ResolveRootfs("foo") + if err == nil { + t.Error("expected error to happen but received nil") + } +} + +func TestExitStatus(t *testing.T) { + status := unix.WaitStatus(0) + ex := ExitStatus(status) + if ex != 0 { + t.Errorf("expected exit status to equal 0 and received %d", ex) + } +} - expected := 5 + len("veth") - if len(name) != expected { - t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) +func TestExitStatusSignaled(t *testing.T) { + status := unix.WaitStatus(2) + ex := ExitStatus(status) + if ex != 130 { + t.Errorf("expected exit status to equal 130 and received %d", ex) } +} - name, err = GenerateRandomName("veth", 65) +func TestWriteJSON(t *testing.T) { + person := struct { + Name string + Age int + }{ + Name: "Alice", + Age: 30, + } + + var b bytes.Buffer + err := WriteJSON(&b, person) if err != nil { t.Fatal(err) } - expected = 64 + len("veth") - if len(name) != expected { - t.Fatalf("expected name to be %d chars but received %d", expected, len(name)) + expected := `{"Name":"Alice","Age":30}` + if b.String() != expected { + t.Errorf("expected to write %s but was %s", expected, b.String()) + } +} + +func TestCleanPath(t *testing.T) { + path := CleanPath("") + if path != "" { + t.Errorf("expected to receive empty string and received %s", path) + } + + path = CleanPath("rootfs") + if path != "rootfs" { + t.Errorf("expected to receive 'rootfs' and received %s", path) + } + + path = CleanPath("../../../var") + if path != "var" { + t.Errorf("expected to receive 'var' and received %s", path) + } + + path = CleanPath("/../../../var") + if path != "/var" { + t.Errorf("expected to receive '/var' and received %s", path) + } + + path = CleanPath("/foo/bar/") + if path != "/foo/bar" { + t.Errorf("expected to receive '/foo/bar' and received %s", path) + } + + path = CleanPath("/foo/bar/../") + if path != "/foo" { + t.Errorf("expected to receive '/foo' and received %s", path) } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go index 408918f27dadd4cdee6738a190d43003fe9d34f5..c96088988a6de8323b7516a6d84423e6dabf6772 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -4,8 +4,10 @@ package utils import ( "io/ioutil" + "os" "strconv" - "syscall" + + "golang.org/x/sys/unix" ) func CloseExecFrom(minFd int) error { @@ -25,9 +27,18 @@ func CloseExecFrom(minFd int) error { continue } - // intentionally ignore errors from syscall.CloseOnExec - syscall.CloseOnExec(fd) + // intentionally ignore errors from unix.CloseOnExec + unix.CloseOnExec(fd) // the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall) } return nil } + +// NewSockPair returns a new unix socket pair +func NewSockPair(name string) (parent *os.File, child *os.File, err error) { + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) + if err != nil { + return nil, nil, err + } + return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil +} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/xattr/errors.go b/vendor/github.com/opencontainers/runc/libcontainer/xattr/errors.go deleted file mode 100644 index 8cd77418ccfbaf7898ad09f83720cde9db7601b7..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/xattr/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package xattr - -import ( - "fmt" - "runtime" -) - -var ErrNotSupportedPlatform = fmt.Errorf("platform and architecture is not supported %s %s", runtime.GOOS, runtime.GOARCH) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go deleted file mode 100644 index 933a75272e28752b9cf249979ac5d6fdc6f7b63b..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_linux.go +++ /dev/null @@ -1,53 +0,0 @@ -// +build linux - -package xattr - -import ( - "syscall" - - "github.com/opencontainers/runc/libcontainer/system" -) - -func XattrEnabled(path string) bool { - if Setxattr(path, "user.test", "") == syscall.ENOTSUP { - return false - } - return true -} - -func stringsfromByte(buf []byte) (result []string) { - offset := 0 - for index, b := range buf { - if b == 0 { - result = append(result, string(buf[offset:index])) - offset = index + 1 - } - } - return -} - -func Listxattr(path string) ([]string, error) { - size, err := system.Llistxattr(path, nil) - if err != nil { - return nil, err - } - buf := make([]byte, size) - read, err := system.Llistxattr(path, buf) - if err != nil { - return nil, err - } - names := stringsfromByte(buf[:read]) - return names, nil -} - -func Getxattr(path, attr string) (string, error) { - value, err := system.Lgetxattr(path, attr) - if err != nil { - return "", err - } - return string(value), nil -} - -func Setxattr(path, xattr, value string) error { - return system.Lsetxattr(path, xattr, []byte(value), 0) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go b/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go deleted file mode 100644 index 1805568a34ba08b18be8f9ebb5900ea5129aa43e..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// +build linux - -package xattr_test - -import ( - "os" - "testing" - - "github.com/opencontainers/runc/libcontainer/xattr" -) - -func TestXattr(t *testing.T) { - tmp := "xattr_test" - out, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0) - if err != nil { - t.Fatal("failed") - } - defer os.Remove(tmp) - attr := "user.test" - out.Close() - - if !xattr.XattrEnabled(tmp) { - t.Log("Disabled") - t.Fatal("failed") - } - t.Log("Success") - - err = xattr.Setxattr(tmp, attr, "test") - if err != nil { - t.Fatal("failed") - } - - var value string - value, err = xattr.Getxattr(tmp, attr) - if err != nil { - t.Fatal("failed") - } - if value != "test" { - t.Fatal("failed") - } - t.Log("Success") - - var names []string - names, err = xattr.Listxattr(tmp) - if err != nil { - t.Fatal("failed") - } - - var found int - for _, name := range names { - if name == attr { - found = 1 - } - } - // Listxattr doesn't return trusted.* and system.* namespace - // attrs when run in unprevileged mode. - if found != 1 { - t.Fatal("failed") - } - t.Log("Success") - - big := "0000000000000000000000000000000000000000000000000000000000000000000008c6419ad822dfe29283fb3ac98dcc5908810cb31f4cfe690040c42c144b7492eicompslf20dxmlpgz" - // Test for long xattrs larger than 128 bytes - err = xattr.Setxattr(tmp, attr, big) - if err != nil { - t.Fatal("failed to add long value") - } - value, err = xattr.Getxattr(tmp, attr) - if err != nil { - t.Fatal("failed to get long value") - } - t.Log("Success") - - if value != big { - t.Fatal("failed, value doesn't match") - } - t.Log("Success") -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go deleted file mode 100644 index 821dea3be1156e5994c3e13ef15465d0fa98a073..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/xattr/xattr_unsupported.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !linux - -package xattr - -func Listxattr(path string) ([]string, error) { - return nil, ErrNotSupportedPlatform -} - -func Getxattr(path, attr string) (string, error) { - return "", ErrNotSupportedPlatform -} - -func Setxattr(path, xattr, value string) error { - return ErrNotSupportedPlatform -} diff --git a/vendor/github.com/opencontainers/runc/list.go b/vendor/github.com/opencontainers/runc/list.go index 894717a9bc754d44705557cbde4c2c99e66c049f..0313d8cc25028381293587a9565c76f222df2e5a 100644 --- a/vendor/github.com/opencontainers/runc/list.go +++ b/vendor/github.com/opencontainers/runc/list.go @@ -7,14 +7,16 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" + "syscall" "text/tabwriter" "time" "encoding/json" - "github.com/sirupsen/logrus" - "github.com/codegangsta/cli" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/user" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/urfave/cli" ) const formatOptions = `table or json` @@ -22,6 +24,8 @@ const formatOptions = `table or json` // containerState represents the platform agnostic pieces relating to a // running container's status and state type containerState struct { + // Version is the OCI version for the container + Version string `json:"ociVersion"` // ID is the container ID ID string `json:"id"` // InitProcessPid is the init process id in the parent namespace @@ -30,56 +34,82 @@ type containerState struct { Status string `json:"status"` // Bundle is the path on the filesystem to the bundle Bundle string `json:"bundle"` + // Rootfs is a path to a directory containing the container's root filesystem. + Rootfs string `json:"rootfs"` // Created is the unix timestamp for the creation time of the container in UTC Created time.Time `json:"created"` + // Annotations is the user defined annotations added to the config. + Annotations map[string]string `json:"annotations,omitempty"` + // The owner of the state directory (the owner of the container). + Owner string `json:"owner"` } var listCommand = cli.Command{ Name: "list", Usage: "lists containers started by runc with the given root", + ArgsUsage: ` + +Where the given root is specified via the global option "--root" +(default: "/run/runc"). + +EXAMPLE 1: +To list containers created via the default "--root": + # runc list + +EXAMPLE 2: +To list containers created using a non-default value for "--root": + # runc --root value list`, Flags: []cli.Flag{ cli.StringFlag{ Name: "format, f", - Value: "", - Usage: `select one of: ` + formatOptions + `. - -The default format is table. The following will output the list of containers -in json format: - - # runc list -f json`, + Value: "table", + Usage: `select one of: ` + formatOptions, + }, + cli.BoolFlag{ + Name: "quiet, q", + Usage: "display only container IDs", }, }, - Action: func(context *cli.Context) { + Action: func(context *cli.Context) error { + if err := checkArgs(context, 0, exactArgs); err != nil { + return err + } s, err := getContainers(context) if err != nil { - logrus.Fatal(err) + return err + } + + if context.Bool("quiet") { + for _, item := range s { + fmt.Println(item.ID) + } + return nil } switch context.String("format") { - case "", "table": + case "table": w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0) - fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\n") + fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n") for _, item := range s { - fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\n", + fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\n", item.ID, item.InitProcessPid, item.Status, item.Bundle, - item.Created.Format(time.RFC3339Nano)) + item.Created.Format(time.RFC3339Nano), + item.Owner) } if err := w.Flush(); err != nil { - logrus.Fatal(err) + return err } case "json": - data, err := json.Marshal(s) - if err != nil { - logrus.Fatal(err) + if err := json.NewEncoder(os.Stdout).Encode(s); err != nil { + return err } - os.Stdout.Write(data) - default: - logrus.Fatal("invalid format option") + return fmt.Errorf("invalid format option") } + return nil }, } @@ -95,44 +125,51 @@ func getContainers(context *cli.Context) ([]containerState, error) { } list, err := ioutil.ReadDir(absRoot) if err != nil { - logrus.Fatal(err) + fatal(err) } var s []containerState for _, item := range list { if item.IsDir() { + // This cast is safe on Linux. + stat := item.Sys().(*syscall.Stat_t) + owner, err := user.LookupUid(int(stat.Uid)) + if err != nil { + owner.Name = fmt.Sprintf("#%d", stat.Uid) + } + container, err := factory.Load(item.Name()) if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "load container %s: %v\n", item.Name(), err) + continue } containerStatus, err := container.Status() if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "status for %s: %v\n", item.Name(), err) + continue } state, err := container.State() if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "state for %s: %v\n", item.Name(), err) + continue + } + pid := state.BaseState.InitProcessPid + if containerStatus == libcontainer.Stopped { + pid = 0 } + bundle, annotations := utils.Annotations(state.Config.Labels) s = append(s, containerState{ + Version: state.BaseState.Config.Version, ID: state.BaseState.ID, - InitProcessPid: state.BaseState.InitProcessPid, + InitProcessPid: pid, Status: containerStatus.String(), - Bundle: searchLabels(state.Config.Labels, "bundle"), - Created: state.BaseState.Created}) + Bundle: bundle, + Rootfs: state.BaseState.Config.Rootfs, + Created: state.BaseState.Created, + Annotations: annotations, + Owner: owner.Name, + }) } } return s, nil } - -func searchLabels(labels []string, query string) string { - for _, l := range labels { - parts := strings.SplitN(l, "=", 2) - if len(parts) < 2 { - continue - } - if parts[0] == query { - return parts[1] - } - } - return "" -} diff --git a/vendor/github.com/opencontainers/runc/main.go b/vendor/github.com/opencontainers/runc/main.go index 259b9d6ef0603a4e2898a9db215434d6175dc56b..072447d17da14be72376343d7d1fc1c8731f3b26 100644 --- a/vendor/github.com/opencontainers/runc/main.go +++ b/vendor/github.com/opencontainers/runc/main.go @@ -2,20 +2,30 @@ package main import ( "fmt" + "io" "os" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/specs/specs-go" + "github.com/urfave/cli" ) +// version will be populated by the Makefile, read from +// VERSION file of the source code. +var version = "" + +// gitCommit will be the hash that the binary was built from +// and will be populated by the Makefile +var gitCommit = "" + const ( - version = "0.0.9" specConfig = "config.json" usage = `Open Container Initiative runtime - + runc is a command line client for running applications packaged according to -the Open Container Format (OCF) and is a compliant implementation of the +the Open Container Initiative (OCI) format and is a compliant implementation of the Open Container Initiative specification. runc integrates well with existing process supervisors to provide a production @@ -25,11 +35,11 @@ direct child of the process supervisor. Containers are configured using bundles. A bundle for a container is a directory that includes a specification file named "` + specConfig + `" and a root filesystem. -The root filesystem contains the contents of the container. +The root filesystem contains the contents of the container. To start a new instance of a container: - # runc start [ -b bundle ] <container-id> + # runc run [ -b bundle ] <container-id> Where "<container-id>" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on @@ -41,7 +51,33 @@ func main() { app := cli.NewApp() app.Name = "runc" app.Usage = usage - app.Version = fmt.Sprintf("%s\nspec version %s", version, specs.Version) + + var v []string + if version != "" { + v = append(v, version) + } + if gitCommit != "" { + v = append(v, fmt.Sprintf("commit: %s", gitCommit)) + } + v = append(v, fmt.Sprintf("spec: %s", specs.Version)) + app.Version = strings.Join(v, "\n") + + root := "/run/runc" + if shouldHonorXDGRuntimeDir() { + if runtimeDir := os.Getenv("XDG_RUNTIME_DIR"); runtimeDir != "" { + root = runtimeDir + "/runc" + // According to the XDG specification, we need to set anything in + // XDG_RUNTIME_DIR to have a sticky bit if we don't want it to get + // auto-pruned. + if err := os.MkdirAll(root, 0700); err != nil { + fatal(err) + } + if err := os.Chmod(root, 0700|os.ModeSticky); err != nil { + fatal(err) + } + } + } + app.Flags = []cli.Flag{ cli.BoolFlag{ Name: "debug", @@ -59,7 +95,7 @@ func main() { }, cli.StringFlag{ Name: "root", - Value: "/run/runc", + Value: root, Usage: "root directory for storage of container state (this should be located in tmpfs)", }, cli.StringFlag{ @@ -67,9 +103,19 @@ func main() { Value: "criu", Usage: "path to the criu binary used for checkpoint and restore", }, + cli.BoolFlag{ + Name: "systemd-cgroup", + Usage: "enable systemd cgroup support, expects cgroupsPath to be of form \"slice:prefix:name\" for e.g. \"system.slice:runc:434234\"", + }, + cli.StringFlag{ + Name: "rootless", + Value: "auto", + Usage: "ignore cgroup permission errors ('true', 'false', or 'auto')", + }, } app.Commands = []cli.Command{ checkpointCommand, + createCommand, deleteCommand, eventsCommand, execCommand, @@ -77,18 +123,21 @@ func main() { killCommand, listCommand, pauseCommand, + psCommand, restoreCommand, resumeCommand, + runCommand, specCommand, startCommand, stateCommand, + updateCommand, } app.Before = func(context *cli.Context) error { if context.GlobalBool("debug") { logrus.SetLevel(logrus.DebugLevel) } if path := context.GlobalString("log"); path != "" { - f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666) if err != nil { return err } @@ -100,11 +149,24 @@ func main() { case "json": logrus.SetFormatter(new(logrus.JSONFormatter)) default: - logrus.Fatalf("unknown log-format %q", context.GlobalString("log-format")) + return fmt.Errorf("unknown log-format %q", context.GlobalString("log-format")) } return nil } + // If the command returns an error, cli takes upon itself to print + // the error on cli.ErrWriter and exit. + // Use our own writer here to ensure the log gets sent to the right location. + cli.ErrWriter = &FatalWriter{cli.ErrWriter} if err := app.Run(os.Args); err != nil { fatal(err) } } + +type FatalWriter struct { + cliErrWriter io.Writer +} + +func (f *FatalWriter) Write(p []byte) (n int, err error) { + logrus.Error(string(p)) + return f.cliErrWriter.Write(p) +} diff --git a/vendor/github.com/opencontainers/runc/main_unix.go b/vendor/github.com/opencontainers/runc/main_unix.go deleted file mode 100644 index 7bbec9fa834e791f97220c094baf1c61054139e5..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/main_unix.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build linux - -package main - -import _ "github.com/opencontainers/runc/libcontainer/nsenter" diff --git a/vendor/github.com/opencontainers/runc/main_unsupported.go b/vendor/github.com/opencontainers/runc/main_unsupported.go deleted file mode 100644 index 3a83f4c10ac17116302beb4ff1bb67212753a2b3..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/main_unsupported.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !linux - -package main - -import "github.com/codegangsta/cli" - -var ( - checkpointCommand cli.Command - eventsCommand cli.Command - restoreCommand cli.Command - specCommand cli.Command - killCommand cli.Command -) - -func runAction(*cli.Context) { - fatalf("Current OS is not supported yet") -} diff --git a/vendor/github.com/opencontainers/runc/notify_socket.go b/vendor/github.com/opencontainers/runc/notify_socket.go new file mode 100644 index 0000000000000000000000000000000000000000..b890b5b1c1af2d1feb26bfd1ec4850e0815546cb --- /dev/null +++ b/vendor/github.com/opencontainers/runc/notify_socket.go @@ -0,0 +1,109 @@ +// +build linux + +package main + +import ( + "bytes" + "fmt" + "net" + "path/filepath" + + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +type notifySocket struct { + socket *net.UnixConn + host string + socketPath string +} + +func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *notifySocket { + if notifySocketHost == "" { + return nil + } + + root := filepath.Join(context.GlobalString("root"), id) + path := filepath.Join(root, "notify.sock") + + notifySocket := ¬ifySocket{ + socket: nil, + host: notifySocketHost, + socketPath: path, + } + + return notifySocket +} + +func (s *notifySocket) Close() error { + return s.socket.Close() +} + +// If systemd is supporting sd_notify protocol, this function will add support +// for sd_notify protocol from within the container. +func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) { + mount := specs.Mount{Destination: s.host, Source: s.socketPath, Options: []string{"bind"}} + spec.Mounts = append(spec.Mounts, mount) + spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host)) +} + +func (s *notifySocket) setupSocket() error { + addr := net.UnixAddr{ + Name: s.socketPath, + Net: "unixgram", + } + + socket, err := net.ListenUnixgram("unixgram", &addr) + if err != nil { + return err + } + + s.socket = socket + return nil +} + +// pid1 must be set only with -d, as it is used to set the new process as the main process +// for the service in systemd +func (s *notifySocket) run(pid1 int) { + buf := make([]byte, 512) + notifySocketHostAddr := net.UnixAddr{Name: s.host, Net: "unixgram"} + client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr) + if err != nil { + logrus.Error(err) + return + } + for { + r, err := s.socket.Read(buf) + if err != nil { + break + } + var out bytes.Buffer + for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) { + if bytes.HasPrefix(line, []byte("READY=")) { + _, err = out.Write(line) + if err != nil { + return + } + + _, err = out.Write([]byte{'\n'}) + if err != nil { + return + } + + _, err = client.Write(out.Bytes()) + if err != nil { + return + } + + // now we can inform systemd to use pid1 as the pid to monitor + if pid1 > 0 { + newPid := fmt.Sprintf("MAINPID=%d\n", pid1) + client.Write([]byte(newPid)) + } + return + } + } + } +} diff --git a/vendor/github.com/opencontainers/runc/pause.go b/vendor/github.com/opencontainers/runc/pause.go index ccec7bbef9d205b2303c1eb7ce25ff172644c58d..224c79f3368d933aaa802fa0b54090d2d9d79d66 100644 --- a/vendor/github.com/opencontainers/runc/pause.go +++ b/vendor/github.com/opencontainers/runc/pause.go @@ -2,7 +2,10 @@ package main -import "github.com/codegangsta/cli" +import ( + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) var pauseCommand = cli.Command{ Name: "pause", @@ -13,15 +16,23 @@ Where "<container-id>" is the name for the instance of the container to be paused. `, Description: `The pause command suspends all processes in the instance of the container. -Use runc list to identiy instances of containers and their current status.`, - Action: func(context *cli.Context) { - container, err := getContainer(context) +Use runc list to identify instances of containers and their current status.`, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + rootlessCg, err := shouldUseRootlessCgroupManager(context) if err != nil { - fatal(err) + return err + } + if rootlessCg { + logrus.Warnf("runc pause may fail if you don't have the full access to cgroups") } - if err := container.Pause(); err != nil { - fatal(err) + container, err := getContainer(context) + if err != nil { + return err } + return container.Pause() }, } @@ -34,14 +45,22 @@ Where "<container-id>" is the name for the instance of the container to be resumed.`, Description: `The resume command resumes all processes in the instance of the container. -Use runc list to identiy instances of containers and their current status.`, - Action: func(context *cli.Context) { - container, err := getContainer(context) +Use runc list to identify instances of containers and their current status.`, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + rootlessCg, err := shouldUseRootlessCgroupManager(context) if err != nil { - fatal(err) + return err + } + if rootlessCg { + logrus.Warn("runc resume may fail if you don't have the full access to cgroups") } - if err := container.Resume(); err != nil { - fatal(err) + container, err := getContainer(context) + if err != nil { + return err } + return container.Resume() }, } diff --git a/vendor/github.com/opencontainers/runc/ps.go b/vendor/github.com/opencontainers/runc/ps.go new file mode 100644 index 0000000000000000000000000000000000000000..e7f635f4f497db97f815a319ae3bcf8f8b9f5337 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/ps.go @@ -0,0 +1,113 @@ +// +build linux + +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +var psCommand = cli.Command{ + Name: "ps", + Usage: "ps displays the processes running inside a container", + ArgsUsage: `<container-id> [ps options]`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format, f", + Value: "table", + Usage: `select one of: ` + formatOptions, + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, minArgs); err != nil { + return err + } + rootlessCg, err := shouldUseRootlessCgroupManager(context) + if err != nil { + return err + } + if rootlessCg { + logrus.Warn("runc ps may fail if you don't have the full access to cgroups") + } + + container, err := getContainer(context) + if err != nil { + return err + } + + pids, err := container.Processes() + if err != nil { + return err + } + + switch context.String("format") { + case "table": + case "json": + return json.NewEncoder(os.Stdout).Encode(pids) + default: + return fmt.Errorf("invalid format option") + } + + // [1:] is to remove command name, ex: + // context.Args(): [containet_id ps_arg1 ps_arg2 ...] + // psArgs: [ps_arg1 ps_arg2 ...] + // + psArgs := context.Args()[1:] + if len(psArgs) == 0 { + psArgs = []string{"-ef"} + } + + cmd := exec.Command("ps", psArgs...) + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("%s: %s", err, output) + } + + lines := strings.Split(string(output), "\n") + pidIndex, err := getPidIndex(lines[0]) + if err != nil { + return err + } + + fmt.Println(lines[0]) + for _, line := range lines[1:] { + if len(line) == 0 { + continue + } + fields := strings.Fields(line) + p, err := strconv.Atoi(fields[pidIndex]) + if err != nil { + return fmt.Errorf("unexpected pid '%s': %s", fields[pidIndex], err) + } + + for _, pid := range pids { + if pid == p { + fmt.Println(line) + break + } + } + } + return nil + }, + SkipArgReorder: true, +} + +func getPidIndex(title string) (int, error) { + titles := strings.Fields(title) + + pidIndex := -1 + for i, name := range titles { + if name == "PID" { + return i, nil + } + } + + return pidIndex, fmt.Errorf("couldn't find PID field in ps output") +} diff --git a/vendor/github.com/opencontainers/runc/restore.go b/vendor/github.com/opencontainers/runc/restore.go index e964df4f121177479718d7a3f19da53b5b1730be..0a08cd12267805da303958836df43b6a3f550374 100644 --- a/vendor/github.com/opencontainers/runc/restore.go +++ b/vendor/github.com/opencontainers/runc/restore.go @@ -4,13 +4,11 @@ package main import ( "os" - "syscall" - "github.com/sirupsen/logrus" - "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/specs/specs-go" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" ) var restoreCommand = cli.Command{ @@ -23,6 +21,11 @@ restored.`, Description: `Restores the saved state of the container instance that was previously saved using the runc checkpoint command.`, Flags: []cli.Flag{ + cli.StringFlag{ + Name: "console-socket", + Value: "", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", + }, cli.StringFlag{ Name: "image-path", Value: "", @@ -52,7 +55,7 @@ using the runc checkpoint command.`, cli.StringFlag{ Name: "manage-cgroups-mode", Value: "", - Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'.", + Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'", }, cli.StringFlag{ Name: "bundle, b", @@ -68,99 +71,55 @@ using the runc checkpoint command.`, Value: "", Usage: "specify the file to write the process id to", }, + cli.BoolFlag{ + Name: "no-subreaper", + Usage: "disable the use of the subreaper used to reap reparented processes", + }, + cli.BoolFlag{ + Name: "no-pivot", + Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", + }, + cli.StringSliceFlag{ + Name: "empty-ns", + Usage: "create a namespace, but don't restore its properties", + }, + cli.BoolFlag{ + Name: "auto-dedup", + Usage: "enable auto deduplication of memory images", + }, + cli.BoolFlag{ + Name: "lazy-pages", + Usage: "use userfaultfd to lazily restore memory pages", + }, }, - Action: func(context *cli.Context) { - imagePath := context.String("image-path") - id := context.Args().First() - if id == "" { - fatal(errEmptyID) + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err } - if imagePath == "" { - imagePath = getDefaultImagePath(context) + // XXX: Currently this is untested with rootless containers. + if os.Geteuid() != 0 || system.RunningInUserNS() { + logrus.Warn("runc checkpoint is untested with rootless containers") } - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } - } - spec, err := loadSpec(specConfig) + + spec, err := setupSpec(context) if err != nil { - fatal(err) + return err } - config, err := createLibcontainerConfig(id, spec) - if err != nil { - fatal(err) + options := criuOptions(context) + if err := setEmptyNsMask(context, options); err != nil { + return err } - status, err := restoreContainer(context, spec, config, imagePath) + status, err := startContainer(context, spec, CT_ACT_RESTORE, options) if err != nil { - fatal(err) + return err } + // exit with the container's exit status so any external supervisor is + // notified of the exit with the correct exit status. os.Exit(status) + return nil }, } -func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Config, imagePath string) (code int, err error) { - var ( - rootuid = 0 - id = context.Args().First() - ) - factory, err := loadFactory(context) - if err != nil { - return -1, err - } - container, err := factory.Load(id) - if err != nil { - container, err = factory.Create(id, config) - if err != nil { - return -1, err - } - } - options := criuOptions(context) - - status, err := container.Status() - if err != nil { - logrus.Error(err) - } - if status == libcontainer.Running { - fatalf("Container with id %s already running", id) - } - - setManageCgroupsMode(context, options) - - // ensure that the container is always removed if we were the process - // that created it. - detach := context.Bool("detach") - if !detach { - defer destroy(container) - } - process := &libcontainer.Process{} - tty, err := setupIO(process, rootuid, "", false, detach) - if err != nil { - return -1, err - } - defer tty.Close() - handler := newSignalHandler(tty) - defer handler.Close() - if err := container.Restore(process, options); err != nil { - return -1, err - } - if err := tty.ClosePostStart(); err != nil { - return -1, err - } - if pidFile := context.String("pid-file"); pidFile != "" { - if err := createPidFile(pidFile, process); err != nil { - process.Signal(syscall.SIGKILL) - process.Wait() - return -1, err - } - } - if detach { - return 0, nil - } - return handler.forward(process) -} - func criuOptions(context *cli.Context) *libcontainer.CriuOpts { imagePath := getCheckpointImagePath(context) if err := os.MkdirAll(imagePath, 0655); err != nil { @@ -169,10 +128,15 @@ func criuOptions(context *cli.Context) *libcontainer.CriuOpts { return &libcontainer.CriuOpts{ ImagesDirectory: imagePath, WorkDirectory: context.String("work-path"), + ParentImage: context.String("parent-path"), LeaveRunning: context.Bool("leave-running"), TcpEstablished: context.Bool("tcp-established"), ExternalUnixConnections: context.Bool("ext-unix-sk"), ShellJob: context.Bool("shell-job"), FileLocks: context.Bool("file-locks"), + PreDump: context.Bool("pre-dump"), + AutoDedup: context.Bool("auto-dedup"), + LazyPages: context.Bool("lazy-pages"), + StatusFd: context.String("status-fd"), } } diff --git a/vendor/github.com/opencontainers/runc/rlimit_linux.go b/vendor/github.com/opencontainers/runc/rlimit_linux.go index a29682808c196bba715c976dfa9c1de3d022d34b..c97a0fb4e8200c7e4bf3ba17824a913cc8380c08 100644 --- a/vendor/github.com/opencontainers/runc/rlimit_linux.go +++ b/vendor/github.com/opencontainers/runc/rlimit_linux.go @@ -22,28 +22,28 @@ const ( ) var rlimitMap = map[string]int{ - "RLIMIT_CPU": RLIMIT_CPU, - "RLIMIT_FSIZE": RLIMIT_FSIZE, - "RLIMIT_DATA": RLIMIT_DATA, - "RLIMIT_STACK": RLIMIT_STACK, - "RLIMIT_CORE": RLIMIT_CORE, - "RLIMIT_RSS": RLIMIT_RSS, - "RLIMIT_NPROC": RLIMIT_NPROC, - "RLIMIT_NOFILE": RLIMIT_NOFILE, - "RLIMIT_MEMLOCK": RLIMIT_MEMLOCK, - "RLIMIT_AS": RLIMIT_AS, - "RLIMIT_LOCKS": RLIMIT_LOCKS, - "RLIMIT_SGPENDING": RLIMIT_SIGPENDING, - "RLIMIT_MSGQUEUE": RLIMIT_MSGQUEUE, - "RLIMIT_NICE": RLIMIT_NICE, - "RLIMIT_RTPRIO": RLIMIT_RTPRIO, - "RLIMIT_RTTIME": RLIMIT_RTTIME, + "RLIMIT_CPU": RLIMIT_CPU, + "RLIMIT_FSIZE": RLIMIT_FSIZE, + "RLIMIT_DATA": RLIMIT_DATA, + "RLIMIT_STACK": RLIMIT_STACK, + "RLIMIT_CORE": RLIMIT_CORE, + "RLIMIT_RSS": RLIMIT_RSS, + "RLIMIT_NPROC": RLIMIT_NPROC, + "RLIMIT_NOFILE": RLIMIT_NOFILE, + "RLIMIT_MEMLOCK": RLIMIT_MEMLOCK, + "RLIMIT_AS": RLIMIT_AS, + "RLIMIT_LOCKS": RLIMIT_LOCKS, + "RLIMIT_SIGPENDING": RLIMIT_SIGPENDING, + "RLIMIT_MSGQUEUE": RLIMIT_MSGQUEUE, + "RLIMIT_NICE": RLIMIT_NICE, + "RLIMIT_RTPRIO": RLIMIT_RTPRIO, + "RLIMIT_RTTIME": RLIMIT_RTTIME, } func strToRlimit(key string) (int, error) { rl, ok := rlimitMap[key] if !ok { - return 0, fmt.Errorf("Wrong rlimit value: %s", key) + return 0, fmt.Errorf("wrong rlimit value: %s", key) } return rl, nil } diff --git a/vendor/github.com/opencontainers/runc/rootless_linux.go b/vendor/github.com/opencontainers/runc/rootless_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..3c425dc655302bd61de3833bc70cecb49761f6ce --- /dev/null +++ b/vendor/github.com/opencontainers/runc/rootless_linux.go @@ -0,0 +1,58 @@ +// +build linux + +package main + +import ( + "os" + + "github.com/opencontainers/runc/libcontainer/system" + "github.com/urfave/cli" +) + +func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) { + if context != nil { + b, err := parseBoolOrAuto(context.GlobalString("rootless")) + if err != nil { + return false, err + } + // nil b stands for "auto detect" + if b != nil { + return *b, nil + } + + if context.GlobalBool("systemd-cgroup") { + return false, nil + } + } + if os.Geteuid() != 0 { + return true, nil + } + if !system.RunningInUserNS() { + // euid == 0 , in the initial ns (i.e. the real root) + return false, nil + } + // euid = 0, in a userns. + // As we are unaware of cgroups path, we can't determine whether we have the full + // access to the cgroups path. + // Either way, we can safely decide to use the rootless cgroups manager. + return true, nil +} + +func shouldHonorXDGRuntimeDir() bool { + if os.Getenv("XDG_RUNTIME_DIR") == "" { + return false + } + if os.Geteuid() != 0 { + return true + } + if !system.RunningInUserNS() { + // euid == 0 , in the initial ns (i.e. the real root) + // in this case, we should use /run/runc and ignore + // $XDG_RUNTIME_DIR (e.g. /run/user/0) for backward + // compatibility. + return false + } + // euid = 0, in a userns. + u, ok := os.LookupEnv("USER") + return !ok || u != "root" +} diff --git a/vendor/github.com/opencontainers/runc/run.go b/vendor/github.com/opencontainers/runc/run.go new file mode 100644 index 0000000000000000000000000000000000000000..f8d6317844d44ea940d14f3e4a30a06191ae2df8 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/run.go @@ -0,0 +1,84 @@ +// +build linux + +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +// default action is to start a container +var runCommand = cli.Command{ + Name: "run", + Usage: "create and run a container", + ArgsUsage: `<container-id> + +Where "<container-id>" is your name for the instance of the container that you +are starting. The name you provide for the container instance must be unique on +your host.`, + Description: `The run command creates an instance of a container for a bundle. The bundle +is a directory with a specification file named "` + specConfig + `" and a root +filesystem. + +The specification file includes an args parameter. The args parameter is used +to specify command(s) that get run when the container is started. To change the +command(s) that get executed on start, edit the args parameter of the spec. See +"runc spec --help" for more explanation.`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "bundle, b", + Value: "", + Usage: `path to the root of the bundle directory, defaults to the current directory`, + }, + cli.StringFlag{ + Name: "console-socket", + Value: "", + Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal", + }, + cli.BoolFlag{ + Name: "detach, d", + Usage: "detach from the container's process", + }, + cli.StringFlag{ + Name: "pid-file", + Value: "", + Usage: "specify the file to write the process id to", + }, + cli.BoolFlag{ + Name: "no-subreaper", + Usage: "disable the use of the subreaper used to reap reparented processes", + }, + cli.BoolFlag{ + Name: "no-pivot", + Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", + }, + cli.BoolFlag{ + Name: "no-new-keyring", + Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key", + }, + cli.IntFlag{ + Name: "preserve-fds", + Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)", + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + if err := revisePidFile(context); err != nil { + return err + } + spec, err := setupSpec(context) + if err != nil { + return err + } + status, err := startContainer(context, spec, CT_ACT_RUN, nil) + if err == nil { + // exit with the container's exit status so any external supervisor is + // notified of the exit with the correct exit status. + os.Exit(status) + } + return err + }, +} diff --git a/vendor/github.com/opencontainers/runc/signalmap.go b/vendor/github.com/opencontainers/runc/signalmap.go new file mode 100644 index 0000000000000000000000000000000000000000..f9a6347730b2b136fe9dd5e70e100166c9295803 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/signalmap.go @@ -0,0 +1,47 @@ +// +build linux +// +build !mips,!mipsle,!mips64,!mips64le + +package main + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +var signalMap = map[string]syscall.Signal{ + "ABRT": unix.SIGABRT, + "ALRM": unix.SIGALRM, + "BUS": unix.SIGBUS, + "CHLD": unix.SIGCHLD, + "CLD": unix.SIGCLD, + "CONT": unix.SIGCONT, + "FPE": unix.SIGFPE, + "HUP": unix.SIGHUP, + "ILL": unix.SIGILL, + "INT": unix.SIGINT, + "IO": unix.SIGIO, + "IOT": unix.SIGIOT, + "KILL": unix.SIGKILL, + "PIPE": unix.SIGPIPE, + "POLL": unix.SIGPOLL, + "PROF": unix.SIGPROF, + "PWR": unix.SIGPWR, + "QUIT": unix.SIGQUIT, + "SEGV": unix.SIGSEGV, + "STKFLT": unix.SIGSTKFLT, + "STOP": unix.SIGSTOP, + "SYS": unix.SIGSYS, + "TERM": unix.SIGTERM, + "TRAP": unix.SIGTRAP, + "TSTP": unix.SIGTSTP, + "TTIN": unix.SIGTTIN, + "TTOU": unix.SIGTTOU, + "URG": unix.SIGURG, + "USR1": unix.SIGUSR1, + "USR2": unix.SIGUSR2, + "VTALRM": unix.SIGVTALRM, + "WINCH": unix.SIGWINCH, + "XCPU": unix.SIGXCPU, + "XFSZ": unix.SIGXFSZ, +} diff --git a/vendor/github.com/opencontainers/runc/signalmap_mipsx.go b/vendor/github.com/opencontainers/runc/signalmap_mipsx.go new file mode 100644 index 0000000000000000000000000000000000000000..046bf1529942b2663e5cf6bfd7413ac3849c1f66 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/signalmap_mipsx.go @@ -0,0 +1,45 @@ +// +build linux,mips linux,mipsle linux,mips64 linux,mips64le + +package main + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +var signalMap = map[string]syscall.Signal{ + "ABRT": unix.SIGABRT, + "ALRM": unix.SIGALRM, + "BUS": unix.SIGBUS, + "CHLD": unix.SIGCHLD, + "CLD": unix.SIGCLD, + "CONT": unix.SIGCONT, + "FPE": unix.SIGFPE, + "HUP": unix.SIGHUP, + "ILL": unix.SIGILL, + "INT": unix.SIGINT, + "IO": unix.SIGIO, + "IOT": unix.SIGIOT, + "KILL": unix.SIGKILL, + "PIPE": unix.SIGPIPE, + "POLL": unix.SIGPOLL, + "PROF": unix.SIGPROF, + "PWR": unix.SIGPWR, + "QUIT": unix.SIGQUIT, + "SEGV": unix.SIGSEGV, + "STOP": unix.SIGSTOP, + "SYS": unix.SIGSYS, + "TERM": unix.SIGTERM, + "TRAP": unix.SIGTRAP, + "TSTP": unix.SIGTSTP, + "TTIN": unix.SIGTTIN, + "TTOU": unix.SIGTTOU, + "URG": unix.SIGURG, + "USR1": unix.SIGUSR1, + "USR2": unix.SIGUSR2, + "VTALRM": unix.SIGVTALRM, + "WINCH": unix.SIGWINCH, + "XCPU": unix.SIGXCPU, + "XFSZ": unix.SIGXFSZ, +} diff --git a/vendor/github.com/opencontainers/runc/signals.go b/vendor/github.com/opencontainers/runc/signals.go index 3e40e5e2c1d7c8494f51ad5842d6a1d263255b7f..b67f65a03e14199a01473ffa316b81ef445a8187 100644 --- a/vendor/github.com/opencontainers/runc/signals.go +++ b/vendor/github.com/opencontainers/runc/signals.go @@ -5,26 +5,37 @@ package main import ( "os" "os/signal" - "syscall" + "syscall" // only for Signal - "github.com/sirupsen/logrus" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/utils" + + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) const signalBufferSize = 2048 // newSignalHandler returns a signal handler for processing SIGCHLD and SIGWINCH signals // while still forwarding all other signals to the process. -func newSignalHandler(tty *tty) *signalHandler { +// If notifySocket is present, use it to read systemd notifications from the container and +// forward them to notifySocketHost. +func newSignalHandler(enableSubreaper bool, notifySocket *notifySocket) *signalHandler { + if enableSubreaper { + // set us as the subreaper before registering the signal handler for the container + if err := system.SetSubreaper(1); err != nil { + logrus.Warn(err) + } + } // ensure that we have a large buffer size so that we do not miss any signals - // incase we are not processing them fast enough. + // in case we are not processing them fast enough. s := make(chan os.Signal, signalBufferSize) // handle all signals for the process. signal.Notify(s) return &signalHandler{ - tty: tty, - signals: s, + signals: s, + notifySocket: notifySocket, } } @@ -36,26 +47,42 @@ type exit struct { } type signalHandler struct { - signals chan os.Signal - tty *tty + signals chan os.Signal + notifySocket *notifySocket } // forward handles the main signal event loop forwarding, resizing, or reaping depending // on the signal received. -func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { +func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach bool) (int, error) { // make sure we know the pid of our main process so that we can return // after it dies. + if detach && h.notifySocket == nil { + return 0, nil + } + pid1, err := process.Pid() if err != nil { return -1, err } - // perform the initial tty resize. - h.tty.resize() + + if h.notifySocket != nil { + if detach { + h.notifySocket.run(pid1) + return 0, nil + } + go h.notifySocket.run(0) + } + + // Perform the initial tty resize. Always ignore errors resizing because + // stdout might have disappeared (due to races with when SIGHUP is sent). + _ = tty.resize() + // Handle and forward signals. for s := range h.signals { switch s { - case syscall.SIGWINCH: - h.tty.resize() - case syscall.SIGCHLD: + case unix.SIGWINCH: + // Ignore errors resizing, as above. + _ = tty.resize() + case unix.SIGCHLD: exits, err := h.reap() if err != nil { logrus.Error(err) @@ -70,12 +97,15 @@ func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { // status because we must ensure that any of the go specific process // fun such as flushing pipes are complete before we return. process.Wait() + if h.notifySocket != nil { + h.notifySocket.Close() + } return e.status, nil } } default: logrus.Debugf("sending signal to process %s", s) - if err := syscall.Kill(pid1, s.(syscall.Signal)); err != nil { + if err := unix.Kill(pid1, s.(syscall.Signal)); err != nil { logrus.Error(err) } } @@ -87,13 +117,13 @@ func (h *signalHandler) forward(process *libcontainer.Process) (int, error) { // then returns all exits to the main event loop for further processing. func (h *signalHandler) reap() (exits []exit, err error) { var ( - ws syscall.WaitStatus - rus syscall.Rusage + ws unix.WaitStatus + rus unix.Rusage ) for { - pid, err := syscall.Wait4(-1, &ws, syscall.WNOHANG, &rus) + pid, err := unix.Wait4(-1, &ws, unix.WNOHANG, &rus) if err != nil { - if err == syscall.ECHILD { + if err == unix.ECHILD { return exits, nil } return nil, err @@ -107,10 +137,3 @@ func (h *signalHandler) reap() (exits []exit, err error) { }) } } - -func (h *signalHandler) Close() error { - if h.tty != nil { - return h.tty.Close() - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/spec.go b/vendor/github.com/opencontainers/runc/spec.go index d5d66fcc9efd1f00ff26ebf6fc3e2506b93bbe5c..322a83d7ad97f024708465f182877a21d3bdec93 100644 --- a/vendor/github.com/opencontainers/runc/spec.go +++ b/vendor/github.com/opencontainers/runc/spec.go @@ -7,140 +7,85 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "syscall" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/seccomp" - libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" - "github.com/opencontainers/specs/specs-go" + "github.com/opencontainers/runc/libcontainer/specconv" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/urfave/cli" ) var specCommand = cli.Command{ - Name: "spec", - Usage: "create a new specification file", - ArgsUsage: "", - Description: `The spec command creates the new specification file named "` + specConfig + `" for the bundle." `, + Name: "spec", + Usage: "create a new specification file", + ArgsUsage: "", + Description: `The spec command creates the new specification file named "` + specConfig + `" for +the bundle. + +The spec generated is just a starter file. Editing of the spec is required to +achieve desired results. For example, the newly generated spec includes an args +parameter that is initially set to call the "sh" command when the container is +started. Calling "sh" may work for an ubuntu container or busybox, but will not +work for containers that do not include the "sh" program. + +EXAMPLE: + To run docker's hello-world container one needs to set the args parameter +in the spec to call hello. This can be done using the sed command or a text +editor. The following commands create a bundle for hello-world, change the +default args parameter in the spec from "sh" to "/hello", then run the hello +command in a new hello-world container named container1: + + mkdir hello + cd hello + docker pull hello-world + docker export $(docker create hello-world) > hello-world.tar + mkdir rootfs + tar -C rootfs -xf hello-world.tar + runc spec + sed -i 's;"sh";"/hello";' ` + specConfig + ` + runc run container1 + +In the run command above, "container1" is the name for the instance of the +container that you are starting. The name you provide for the container instance +must be unique on your host. + +An alternative for generating a customized spec config is to use "oci-runtime-tool", the +sub-command "oci-runtime-tool generate" has lots of options that can be used to do any +customizations as you want, see runtime-tools (https://github.com/opencontainers/runtime-tools) +to get more information. + +When starting a container through runc, runc needs root privilege. If not +already running as root, you can use sudo to give runc root privilege. For +example: "sudo runc start container1" will give runc root privilege to start the +container on your host. + +Alternatively, you can start a rootless container, which has the ability to run +without root privileges. For this to work, the specification file needs to be +adjusted accordingly. You can pass the parameter --rootless to this command to +generate a proper rootless spec file. + +Note that --rootless is not needed when you execute runc as the root in a user namespace +created by an unprivileged user. +`, Flags: []cli.Flag{ cli.StringFlag{ Name: "bundle, b", Value: "", Usage: "path to the root of the bundle directory", }, + cli.BoolFlag{ + Name: "rootless", + Usage: "generate a configuration for a rootless container", + }, }, - Action: func(context *cli.Context) { - spec := specs.Spec{ - Version: specs.Version, - Platform: specs.Platform{ - OS: runtime.GOOS, - Arch: runtime.GOARCH, - }, - Root: specs.Root{ - Path: "rootfs", - Readonly: true, - }, - Process: specs.Process{ - Terminal: true, - User: specs.User{}, - Args: []string{ - "sh", - }, - Env: []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM=xterm", - }, - Cwd: "/", - NoNewPrivileges: true, - Capabilities: []string{ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE", - }, - Rlimits: []specs.Rlimit{ - { - Type: "RLIMIT_NOFILE", - Hard: uint64(1024), - Soft: uint64(1024), - }, - }, - }, - Hostname: "runc", - Mounts: []specs.Mount{ - { - Destination: "/proc", - Type: "proc", - Source: "proc", - Options: nil, - }, - { - Destination: "/dev", - Type: "tmpfs", - Source: "tmpfs", - Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, - }, - { - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, - }, - { - Destination: "/dev/shm", - Type: "tmpfs", - Source: "shm", - Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, - }, - { - Destination: "/dev/mqueue", - Type: "mqueue", - Source: "mqueue", - Options: []string{"nosuid", "noexec", "nodev"}, - }, - { - Destination: "/sys", - Type: "sysfs", - Source: "sysfs", - Options: []string{"nosuid", "noexec", "nodev", "ro"}, - }, - { - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, - }, - }, - Linux: specs.Linux{ - Resources: &specs.Resources{ - Devices: []specs.DeviceCgroup{ - { - Allow: false, - Access: sPtr("rwm"), - }, - }, - }, - Namespaces: []specs.Namespace{ - { - Type: "pid", - }, - { - Type: "network", - }, - { - Type: "ipc", - }, - { - Type: "uts", - }, - { - Type: "mount", - }, - }, - }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 0, exactArgs); err != nil { + return err + } + spec := specconv.Example() + + rootless := context.Bool("rootless") + if rootless { + specconv.ToRootless(spec) } checkNoFile := func(name string) error { @@ -156,61 +101,21 @@ var specCommand = cli.Command{ bundle := context.String("bundle") if bundle != "" { if err := os.Chdir(bundle); err != nil { - fatal(err) + return err } } if err := checkNoFile(specConfig); err != nil { - fatal(err) + return err } - data, err := json.MarshalIndent(&spec, "", "\t") + data, err := json.MarshalIndent(spec, "", "\t") if err != nil { - fatal(err) - } - if err := ioutil.WriteFile(specConfig, data, 0666); err != nil { - fatal(err) + return err } + return ioutil.WriteFile(specConfig, data, 0666) }, } -func sPtr(s string) *string { return &s } -func rPtr(r rune) *rune { return &r } -func iPtr(i int64) *int64 { return &i } -func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } -func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } - -var namespaceMapping = map[specs.NamespaceType]configs.NamespaceType{ - specs.PIDNamespace: configs.NEWPID, - specs.NetworkNamespace: configs.NEWNET, - specs.MountNamespace: configs.NEWNS, - specs.UserNamespace: configs.NEWUSER, - specs.IPCNamespace: configs.NEWIPC, - specs.UTSNamespace: configs.NEWUTS, -} - -var mountPropagationMapping = map[string]int{ - "rprivate": syscall.MS_PRIVATE | syscall.MS_REC, - "private": syscall.MS_PRIVATE, - "rslave": syscall.MS_SLAVE | syscall.MS_REC, - "slave": syscall.MS_SLAVE, - "rshared": syscall.MS_SHARED | syscall.MS_REC, - "shared": syscall.MS_SHARED, - "": syscall.MS_PRIVATE | syscall.MS_REC, -} - -// validateSpec validates the fields in the spec -// TODO: Add validation for other fields where applicable -func validateSpec(spec *specs.Spec) error { - if spec.Process.Cwd == "" { - return fmt.Errorf("Cwd property must not be empty") - } - if !filepath.IsAbs(spec.Process.Cwd) { - return fmt.Errorf("Cwd must be an absolute path") - } - return nil -} - // loadSpec loads the specification from the provided path. -// If the path is empty then the default path will be "config.json" func loadSpec(cPath string) (spec *specs.Spec, err error) { cf, err := os.Open(cPath) if err != nil { @@ -224,575 +129,17 @@ func loadSpec(cPath string) (spec *specs.Spec, err error) { if err = json.NewDecoder(cf).Decode(&spec); err != nil { return nil, err } - return spec, validateSpec(spec) -} - -func createLibcontainerConfig(cgroupName string, spec *specs.Spec) (*configs.Config, error) { - // runc's cwd will always be the bundle path - rcwd, err := os.Getwd() - if err != nil { - return nil, err - } - cwd, err := filepath.Abs(rcwd) - if err != nil { - return nil, err - } - rootfsPath := spec.Root.Path - if !filepath.IsAbs(rootfsPath) { - rootfsPath = filepath.Join(cwd, rootfsPath) - } - config := &configs.Config{ - Rootfs: rootfsPath, - Readonlyfs: spec.Root.Readonly, - Hostname: spec.Hostname, - Labels: []string{ - "bundle=" + cwd, - }, - } - - exists := false - if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists { - return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation) - } - - for _, ns := range spec.Linux.Namespaces { - t, exists := namespaceMapping[ns.Type] - if !exists { - return nil, fmt.Errorf("namespace %q does not exist", ns) - } - config.Namespaces.Add(t, ns.Path) - } - if config.Namespaces.Contains(configs.NEWNET) { - config.Networks = []*configs.Network{ - { - Type: "loopback", - }, - } - } - for _, m := range spec.Mounts { - config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m)) - } - if err := createDevices(spec, config); err != nil { - return nil, err - } - if err := setupUserNamespace(spec, config); err != nil { - return nil, err - } - c, err := createCgroupConfig(cgroupName, spec) - if err != nil { - return nil, err - } - config.Cgroups = c - // set extra path masking for libcontainer for the various unsafe places in proc - config.MaskPaths = maskedPaths - config.ReadonlyPaths = readonlyPaths - if spec.Linux.Seccomp != nil { - seccomp, err := setupSeccomp(spec.Linux.Seccomp) - if err != nil { - return nil, err - } - config.Seccomp = seccomp - } - config.Sysctl = spec.Linux.Sysctl - if oomScoreAdj := spec.Linux.Resources.OOMScoreAdj; oomScoreAdj != nil { - config.OomScoreAdj = *oomScoreAdj - } - for _, g := range spec.Process.User.AdditionalGids { - config.AdditionalGroups = append(config.AdditionalGroups, strconv.FormatUint(uint64(g), 10)) - } - createHooks(spec, config) - config.Version = specs.Version - return config, nil -} - -func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount { - flags, pgflags, data := parseMountOptions(m.Options) - source := m.Source - if m.Type == "bind" { - if !filepath.IsAbs(source) { - source = filepath.Join(cwd, m.Source) - } - } - return &configs.Mount{ - Device: m.Type, - Source: source, - Destination: m.Destination, - Data: data, - Flags: flags, - PropagationFlags: pgflags, - } -} - -func createCgroupConfig(name string, spec *specs.Spec) (*configs.Cgroup, error) { - var ( - err error - myCgroupPath string - ) - - if spec.Linux.CgroupsPath != nil { - myCgroupPath = libcontainerUtils.CleanPath(*spec.Linux.CgroupsPath) - } else { - myCgroupPath, err = cgroups.GetThisCgroupDir("devices") - if err != nil { - return nil, err - } - myCgroupPath = filepath.Join(myCgroupPath, name) - } - - c := &configs.Cgroup{ - Path: myCgroupPath, - Resources: &configs.Resources{}, - } - c.Resources.AllowedDevices = allowedDevices - r := spec.Linux.Resources - if r == nil { - return c, nil - } - for i, d := range spec.Linux.Resources.Devices { - var ( - t = "a" - major = int64(-1) - minor = int64(-1) - ) - if d.Type != nil { - t = *d.Type - } - if d.Major != nil { - major = *d.Major - } - if d.Minor != nil { - minor = *d.Minor - } - if d.Access == nil || *d.Access == "" { - return nil, fmt.Errorf("device access at %d field canot be empty", i) - } - dt, err := stringToDeviceRune(t) - if err != nil { - return nil, err - } - dd := &configs.Device{ - Type: dt, - Major: major, - Minor: minor, - Permissions: *d.Access, - Allow: d.Allow, - } - c.Resources.Devices = append(c.Resources.Devices, dd) - } - // append the default allowed devices to the end of the list - c.Resources.Devices = append(c.Resources.Devices, allowedDevices...) - if r.Memory != nil { - if r.Memory.Limit != nil { - c.Resources.Memory = int64(*r.Memory.Limit) - } - if r.Memory.Reservation != nil { - c.Resources.MemoryReservation = int64(*r.Memory.Reservation) - } - if r.Memory.Swap != nil { - c.Resources.MemorySwap = int64(*r.Memory.Swap) - } - if r.Memory.Kernel != nil { - c.Resources.KernelMemory = int64(*r.Memory.Kernel) - } - if r.Memory.Swappiness != nil { - swappiness := int64(*r.Memory.Swappiness) - c.Resources.MemorySwappiness = &swappiness - } - } - if r.CPU != nil { - if r.CPU.Shares != nil { - c.Resources.CpuShares = int64(*r.CPU.Shares) - } - if r.CPU.Quota != nil { - c.Resources.CpuQuota = int64(*r.CPU.Quota) - } - if r.CPU.Period != nil { - c.Resources.CpuPeriod = int64(*r.CPU.Period) - } - if r.CPU.RealtimeRuntime != nil { - c.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime) - } - if r.CPU.RealtimePeriod != nil { - c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod) - } - if r.CPU.Cpus != nil { - c.Resources.CpusetCpus = *r.CPU.Cpus - } - if r.CPU.Mems != nil { - c.Resources.CpusetMems = *r.CPU.Mems - } - } - if r.Pids != nil { - c.Resources.PidsLimit = *r.Pids.Limit - } - if r.BlockIO != nil { - if r.BlockIO.Weight != nil { - c.Resources.BlkioWeight = *r.BlockIO.Weight - } - if r.BlockIO.LeafWeight != nil { - c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight - } - if r.BlockIO.WeightDevice != nil { - for _, wd := range r.BlockIO.WeightDevice { - weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, *wd.Weight, *wd.LeafWeight) - c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice) - } - } - if r.BlockIO.ThrottleReadBpsDevice != nil { - for _, td := range r.BlockIO.ThrottleReadBpsDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleWriteBpsDevice != nil { - for _, td := range r.BlockIO.ThrottleWriteBpsDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleReadIOPSDevice != nil { - for _, td := range r.BlockIO.ThrottleReadIOPSDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice) - } - } - if r.BlockIO.ThrottleWriteIOPSDevice != nil { - for _, td := range r.BlockIO.ThrottleWriteIOPSDevice { - throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, *td.Rate) - c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice) - } - } - } - for _, l := range r.HugepageLimits { - c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{ - Pagesize: *l.Pagesize, - Limit: *l.Limit, - }) - } - if r.DisableOOMKiller != nil { - c.Resources.OomKillDisable = *r.DisableOOMKiller - } - if r.Network != nil { - if r.Network.ClassID != nil { - c.Resources.NetClsClassid = string(*r.Network.ClassID) - } - for _, m := range r.Network.Priorities { - c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{ - Interface: m.Name, - Priority: int64(m.Priority), - }) - } - } - return c, nil -} - -func stringToDeviceRune(s string) (rune, error) { - switch s { - case "a": - return 'a', nil - case "b": - return 'b', nil - case "c": - return 'c', nil - default: - return 0, fmt.Errorf("invalid device type %q", s) - } + return spec, validateProcessSpec(spec.Process) } -func createDevices(spec *specs.Spec, config *configs.Config) error { - // add whitelisted devices - config.Devices = []*configs.Device{ - { - Type: 'c', - Path: "/dev/null", - Major: 1, - Minor: 3, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/random", - Major: 1, - Minor: 8, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/full", - Major: 1, - Minor: 7, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/tty", - Major: 5, - Minor: 0, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/zero", - Major: 1, - Minor: 5, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - { - Type: 'c', - Path: "/dev/urandom", - Major: 1, - Minor: 9, - FileMode: 0666, - Uid: 0, - Gid: 0, - }, - } - // merge in additional devices from the spec - for _, d := range spec.Linux.Devices { - var uid, gid uint32 - if d.UID != nil { - uid = *d.UID - } - if d.GID != nil { - gid = *d.GID - } - dt, err := stringToDeviceRune(d.Type) - if err != nil { - return err - } - device := &configs.Device{ - Type: dt, - Path: d.Path, - Major: d.Major, - Minor: d.Minor, - FileMode: *d.FileMode, - Uid: uid, - Gid: gid, - } - config.Devices = append(config.Devices, device) - } - return nil -} - -func setupUserNamespace(spec *specs.Spec, config *configs.Config) error { - if len(spec.Linux.UIDMappings) == 0 { - return nil - } - // do not override the specified user namespace path - if config.Namespaces.PathOf(configs.NEWUSER) == "" { - config.Namespaces.Add(configs.NEWUSER, "") - } - create := func(m specs.IDMapping) configs.IDMap { - return configs.IDMap{ - HostID: int(m.HostID), - ContainerID: int(m.ContainerID), - Size: int(m.Size), - } - } - for _, m := range spec.Linux.UIDMappings { - config.UidMappings = append(config.UidMappings, create(m)) - } - for _, m := range spec.Linux.GIDMappings { - config.GidMappings = append(config.GidMappings, create(m)) - } - rootUID, err := config.HostUID() - if err != nil { - return err - } - rootGID, err := config.HostGID() - if err != nil { - return err - } - for _, node := range config.Devices { - node.Uid = uint32(rootUID) - node.Gid = uint32(rootGID) - } - return nil -} - -func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) { +func createLibContainerRlimit(rlimit specs.POSIXRlimit) (configs.Rlimit, error) { rl, err := strToRlimit(rlimit.Type) if err != nil { return configs.Rlimit{}, err } return configs.Rlimit{ Type: rl, - Hard: uint64(rlimit.Hard), - Soft: uint64(rlimit.Soft), + Hard: rlimit.Hard, + Soft: rlimit.Soft, }, nil } - -// parseMountOptions parses the string and returns the flags, propagation -// flags and any mount data that it contains. -func parseMountOptions(options []string) (int, []int, string) { - var ( - flag int - pgflag []int - data []string - ) - flags := map[string]struct { - clear bool - flag int - }{ - "async": {true, syscall.MS_SYNCHRONOUS}, - "atime": {true, syscall.MS_NOATIME}, - "bind": {false, syscall.MS_BIND}, - "defaults": {false, 0}, - "dev": {true, syscall.MS_NODEV}, - "diratime": {true, syscall.MS_NODIRATIME}, - "dirsync": {false, syscall.MS_DIRSYNC}, - "exec": {true, syscall.MS_NOEXEC}, - "mand": {false, syscall.MS_MANDLOCK}, - "noatime": {false, syscall.MS_NOATIME}, - "nodev": {false, syscall.MS_NODEV}, - "nodiratime": {false, syscall.MS_NODIRATIME}, - "noexec": {false, syscall.MS_NOEXEC}, - "nomand": {true, syscall.MS_MANDLOCK}, - "norelatime": {true, syscall.MS_RELATIME}, - "nostrictatime": {true, syscall.MS_STRICTATIME}, - "nosuid": {false, syscall.MS_NOSUID}, - "rbind": {false, syscall.MS_BIND | syscall.MS_REC}, - "relatime": {false, syscall.MS_RELATIME}, - "remount": {false, syscall.MS_REMOUNT}, - "ro": {false, syscall.MS_RDONLY}, - "rw": {true, syscall.MS_RDONLY}, - "strictatime": {false, syscall.MS_STRICTATIME}, - "suid": {true, syscall.MS_NOSUID}, - "sync": {false, syscall.MS_SYNCHRONOUS}, - } - propagationFlags := map[string]struct { - clear bool - flag int - }{ - "private": {false, syscall.MS_PRIVATE}, - "shared": {false, syscall.MS_SHARED}, - "slave": {false, syscall.MS_SLAVE}, - "unbindable": {false, syscall.MS_UNBINDABLE}, - "rprivate": {false, syscall.MS_PRIVATE | syscall.MS_REC}, - "rshared": {false, syscall.MS_SHARED | syscall.MS_REC}, - "rslave": {false, syscall.MS_SLAVE | syscall.MS_REC}, - "runbindable": {false, syscall.MS_UNBINDABLE | syscall.MS_REC}, - } - for _, o := range options { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else if f, exists := propagationFlags[o]; exists && f.flag != 0 { - pgflag = append(pgflag, f.flag) - } else { - data = append(data, o) - } - } - return flag, pgflag, strings.Join(data, ",") -} - -func setupSeccomp(config *specs.Seccomp) (*configs.Seccomp, error) { - if config == nil { - return nil, nil - } - - // No default action specified, no syscalls listed, assume seccomp disabled - if config.DefaultAction == "" && len(config.Syscalls) == 0 { - return nil, nil - } - - newConfig := new(configs.Seccomp) - newConfig.Syscalls = []*configs.Syscall{} - - if len(config.Architectures) > 0 { - newConfig.Architectures = []string{} - for _, arch := range config.Architectures { - newArch, err := seccomp.ConvertStringToArch(string(arch)) - if err != nil { - return nil, err - } - newConfig.Architectures = append(newConfig.Architectures, newArch) - } - } - - // Convert default action from string representation - newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction)) - if err != nil { - return nil, err - } - newConfig.DefaultAction = newDefaultAction - - // Loop through all syscall blocks and convert them to libcontainer format - for _, call := range config.Syscalls { - newAction, err := seccomp.ConvertStringToAction(string(call.Action)) - if err != nil { - return nil, err - } - - newCall := configs.Syscall{ - Name: call.Name, - Action: newAction, - Args: []*configs.Arg{}, - } - - // Loop through all the arguments of the syscall and convert them - for _, arg := range call.Args { - newOp, err := seccomp.ConvertStringToOperator(string(arg.Op)) - if err != nil { - return nil, err - } - - newArg := configs.Arg{ - Index: arg.Index, - Value: arg.Value, - ValueTwo: arg.ValueTwo, - Op: newOp, - } - - newCall.Args = append(newCall.Args, &newArg) - } - - newConfig.Syscalls = append(newConfig.Syscalls, &newCall) - } - - return newConfig, nil -} - -func createHooks(rspec *specs.Spec, config *configs.Config) { - config.Hooks = &configs.Hooks{} - for _, h := range rspec.Hooks.Prestart { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd)) - } - for _, h := range rspec.Hooks.Poststart { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Poststart = append(config.Hooks.Poststart, configs.NewCommandHook(cmd)) - } - for _, h := range rspec.Hooks.Poststop { - cmd := configs.Command{ - Path: h.Path, - Args: h.Args, - Env: h.Env, - } - config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd)) - } -} diff --git a/vendor/github.com/opencontainers/runc/spec_test.go b/vendor/github.com/opencontainers/runc/spec_test.go deleted file mode 100644 index 156ee62cdd98e05704f1d8a96e4307d866a16d9d..0000000000000000000000000000000000000000 --- a/vendor/github.com/opencontainers/runc/spec_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// build +linux - -package main - -import ( - "strings" - "testing" - - "github.com/opencontainers/specs/specs-go" -) - -func TestLinuxCgroupsPathSpecified(t *testing.T) { - cgroupsPath := "/user/cgroups/path/id" - - spec := &specs.Spec{} - spec.Linux.CgroupsPath = &cgroupsPath - - cgroup, err := createCgroupConfig("ContainerID", spec) - if err != nil { - t.Errorf("Couldn't create Cgroup config: %v", err) - } - - if cgroup.Path != cgroupsPath { - t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path) - } -} - -func TestLinuxCgroupsPathNotSpecified(t *testing.T) { - spec := &specs.Spec{} - - cgroup, err := createCgroupConfig("ContainerID", spec) - if err != nil { - t.Errorf("Couldn't create Cgroup config: %v", err) - } - - if !strings.HasSuffix(cgroup.Path, "/ContainerID") { - t.Errorf("Wrong cgroupsPath, expected it to have suffix '%s' got '%s'", "/ContainerID", cgroup.Path) - } -} diff --git a/vendor/github.com/opencontainers/runc/start.go b/vendor/github.com/opencontainers/runc/start.go index f846bd1e9ffa172efaffd0332dba19dbc318db9d..2bb698b20952985f3a7aaee4f79b691e3f241f63 100644 --- a/vendor/github.com/opencontainers/runc/start.go +++ b/vendor/github.com/opencontainers/runc/start.go @@ -1,123 +1,43 @@ -// +build linux - package main import ( - "os" - "runtime" + "errors" + "fmt" - "github.com/codegangsta/cli" - "github.com/coreos/go-systemd/activation" "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/specs/specs-go" + "github.com/urfave/cli" ) -// default action is to start a container var startCommand = cli.Command{ Name: "start", - Usage: "create and run a container", + Usage: "executes the user defined process in a created container", ArgsUsage: `<container-id> Where "<container-id>" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host.`, - Description: `The start command creates an instance of a container for a bundle. The bundle -is a directory with a specification file and a root filesystem.`, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "bundle, b", - Value: "", - Usage: `path to the root of the bundle directory, defaults to the current directory`, - }, - cli.StringFlag{ - Name: "console", - Value: "", - Usage: "specify the pty slave path for use with the container", - }, - cli.BoolFlag{ - Name: "detach,d", - Usage: "detach from the container's process", - }, - cli.StringFlag{ - Name: "pid-file", - Value: "", - Usage: "specify the file to write the process id to", - }, - }, - Action: func(context *cli.Context) { - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } + Description: `The start command executes the user defined process in a created container.`, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err } - spec, err := loadSpec(specConfig) + container, err := getContainer(context) if err != nil { - fatal(err) - } - - notifySocket := os.Getenv("NOTIFY_SOCKET") - if notifySocket != "" { - setupSdNotify(spec, notifySocket) + return err } - - if os.Geteuid() != 0 { - fatalf("runc should be run as root") - } - - status, err := startContainer(context, spec) + status, err := container.Status() if err != nil { - fatalf("Container start failed: %v", err) + return err } - // exit with the container's exit status so any external supervisor is - // notified of the exit with the correct exit status. - os.Exit(status) - }, -} - -var initCommand = cli.Command{ - Name: "init", - Usage: `init is used to initialize the containers namespaces and launch the users process. - This command should not be called outside of runc. - `, - Action: func(context *cli.Context) { - runtime.GOMAXPROCS(1) - runtime.LockOSThread() - factory, _ := libcontainer.New("") - if err := factory.StartInitialization(); err != nil { - fatal(err) + switch status { + case libcontainer.Created: + return container.Exec() + case libcontainer.Stopped: + return errors.New("cannot start a container that has stopped") + case libcontainer.Running: + return errors.New("cannot start an already running container") + default: + return fmt.Errorf("cannot start a container in the %s state\n", status) } - panic("libcontainer: container init failed to exec") }, } - -func startContainer(context *cli.Context, spec *specs.Spec) (int, error) { - id := context.Args().First() - if id == "" { - return -1, errEmptyID - } - container, err := createContainer(context, id, spec) - if err != nil { - return -1, err - } - - // ensure that the container is always removed if we were the process - // that created it. - detach := context.Bool("detach") - if !detach { - defer destroy(container) - } - - // Support on-demand socket activation by passing file descriptors into the container init process. - listenFDs := []*os.File{} - if os.Getenv("LISTEN_FDS") != "" { - listenFDs = activation.Files(false) - } - - status, err := runProcess(container, &spec.Process, listenFDs, context.String("console"), context.String("pid-file"), detach) - if err != nil { - destroy(container) - return -1, err - } - return status, nil -} diff --git a/vendor/github.com/opencontainers/runc/state.go b/vendor/github.com/opencontainers/runc/state.go index 0b1fbc9b9c22bbceb9415c683f9acde8d96744a0..718813c36bef6ed944709bf4a162ed85d959d929 100644 --- a/vendor/github.com/opencontainers/runc/state.go +++ b/vendor/github.com/opencontainers/runc/state.go @@ -5,32 +5,12 @@ package main import ( "encoding/json" "os" - "time" - "github.com/codegangsta/cli" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/urfave/cli" ) -// cState represents the platform agnostic pieces relating to a running -// container's status and state. Note: The fields in this structure adhere to -// the opencontainers/specs/specs-go requirement for json fields that must be returned -// in a state command. -type cState struct { - // Version is the OCI version for the container - Version string `json:"ociVersion"` - // ID is the container ID - ID string `json:"id"` - // InitProcessPid is the init process id in the parent namespace - InitProcessPid int `json:"pid"` - // Bundle is the path on the filesystem to the bundle - Bundle string `json:"bundlePath"` - // Rootfs is a path to a directory containing the container's root filesystem. - Rootfs string `json:"rootfsPath"` - // Status is the current status of the container, running, paused, ... - Status string `json:"status"` - // Created is the unix timestamp for the creation time of the container in UTC - Created time.Time `json:"created"` -} - var stateCommand = cli.Command{ Name: "state", Usage: "output the state of a container", @@ -39,31 +19,42 @@ var stateCommand = cli.Command{ Where "<container-id>" is your name for the instance of the container.`, Description: `The state command outputs current state information for the instance of a container.`, - Action: func(context *cli.Context) { + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } container, err := getContainer(context) if err != nil { - fatal(err) + return err } containerStatus, err := container.Status() if err != nil { - fatal(err) + return err } state, err := container.State() if err != nil { - fatal(err) + return err } - cs := cState{ + pid := state.BaseState.InitProcessPid + if containerStatus == libcontainer.Stopped { + pid = 0 + } + bundle, annotations := utils.Annotations(state.Config.Labels) + cs := containerState{ Version: state.BaseState.Config.Version, ID: state.BaseState.ID, - InitProcessPid: state.BaseState.InitProcessPid, + InitProcessPid: pid, Status: containerStatus.String(), - Bundle: searchLabels(state.Config.Labels, "bundle"), + Bundle: bundle, Rootfs: state.BaseState.Config.Rootfs, - Created: state.BaseState.Created} + Created: state.BaseState.Created, + Annotations: annotations, + } data, err := json.MarshalIndent(cs, "", " ") if err != nil { - fatal(err) + return err } os.Stdout.Write(data) + return nil }, } diff --git a/vendor/github.com/opencontainers/runc/tty.go b/vendor/github.com/opencontainers/runc/tty.go index fd531068fe7abc151a7ec9c55ee53d95befb9b31..6106c2db36879a4fcf8d153ebb05a3cace9d86c2 100644 --- a/vendor/github.com/opencontainers/runc/tty.go +++ b/vendor/github.com/opencontainers/runc/tty.go @@ -6,26 +6,34 @@ import ( "fmt" "io" "os" + "os/signal" "sync" - "github.com/docker/docker/pkg/term" + "github.com/containerd/console" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/utils" ) -// newTty creates a new tty for use with the container. If a tty is not to be -// created for the process, pipes are created so that the TTY of the parent -// process are not inherited by the container. -func newTty(create bool, p *libcontainer.Process, rootuid int, console string) (*tty, error) { - if create { - return createTty(p, rootuid, console) - } - return createStdioPipes(p, rootuid) +type tty struct { + epoller *console.Epoller + console *console.EpollConsole + stdin console.Console + closers []io.Closer + postStart []io.Closer + wg sync.WaitGroup + consoleC chan error +} + +func (t *tty) copyIO(w io.Writer, r io.ReadCloser) { + defer t.wg.Done() + io.Copy(w, r) + r.Close() } -// setup standard pipes so that the TTY of the calling runc process -// is not inherited by the container. -func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) { - i, err := p.InitializeIO(rootuid) +// setup pipes for the process so that advanced features like c/r are able to easily checkpoint +// and restore the process's IO without depending on a host specific path or device +func setupProcessPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) { + i, err := p.InitializeIO(rootuid, rootgid) if err != nil { return nil, err } @@ -56,45 +64,71 @@ func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) { return t, nil } -func (t *tty) copyIO(w io.Writer, r io.ReadCloser) { - defer t.wg.Done() - io.Copy(w, r) - r.Close() +func inheritStdio(process *libcontainer.Process) error { + process.Stdin = os.Stdin + process.Stdout = os.Stdout + process.Stderr = os.Stderr + return nil } -func createTty(p *libcontainer.Process, rootuid int, consolePath string) (*tty, error) { - if consolePath != "" { - if err := p.ConsoleFromPath(consolePath); err != nil { - return nil, err - } - return &tty{}, nil +func (t *tty) recvtty(process *libcontainer.Process, socket *os.File) (Err error) { + f, err := utils.RecvFd(socket) + if err != nil { + return err } - console, err := p.NewConsole(rootuid) + cons, err := console.ConsoleFromFile(f) if err != nil { - return nil, err + return err + } + console.ClearONLCR(cons.Fd()) + epoller, err := console.NewEpoller() + if err != nil { + return err } - go io.Copy(console, os.Stdin) - go io.Copy(os.Stdout, console) + epollConsole, err := epoller.Add(cons) + if err != nil { + return err + } + defer func() { + if Err != nil { + epollConsole.Close() + } + }() + go epoller.Wait() + go io.Copy(epollConsole, os.Stdin) + t.wg.Add(1) + go t.copyIO(os.Stdout, epollConsole) - state, err := term.SetRawTerminal(os.Stdin.Fd()) + // set raw mode to stdin and also handle interrupt + stdin, err := console.ConsoleFromFile(os.Stdin) if err != nil { - return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err) + return err } - return &tty{ - console: console, - state: state, - closers: []io.Closer{ - console, - }, - }, nil + if err := stdin.SetRaw(); err != nil { + return fmt.Errorf("failed to set the terminal from the stdin: %v", err) + } + go handleInterrupt(stdin) + + t.epoller = epoller + t.stdin = stdin + t.console = epollConsole + t.closers = []io.Closer{epollConsole} + return nil } -type tty struct { - console libcontainer.Console - state *term.State - closers []io.Closer - postStart []io.Closer - wg sync.WaitGroup +func handleInterrupt(c console.Console) { + sigchan := make(chan os.Signal, 1) + signal.Notify(sigchan, os.Interrupt) + <-sigchan + c.Reset() + os.Exit(0) +} + +func (t *tty) waitConsole() error { + if t.consoleC != nil { + return <-t.consoleC + } + return nil } // ClosePostStart closes any fds that are provided to the container and dup2'd @@ -106,20 +140,24 @@ func (t *tty) ClosePostStart() error { return nil } -// Close closes all open fds for the tty and/or restores the orignal +// Close closes all open fds for the tty and/or restores the original // stdin state to what it was prior to the container execution func (t *tty) Close() error { // ensure that our side of the fds are always closed for _, c := range t.postStart { c.Close() } - // wait for the copy routines to finish before closing the fds + // the process is gone at this point, shutting down the console if we have + // one and wait for all IO to be finished + if t.console != nil && t.epoller != nil { + t.console.Shutdown(t.epoller.CloseConsole) + } t.wg.Wait() for _, c := range t.closers { c.Close() } - if t.state != nil { - term.RestoreTerminal(os.Stdin.Fd(), t.state) + if t.stdin != nil { + t.stdin.Reset() } return nil } @@ -128,9 +166,5 @@ func (t *tty) resize() error { if t.console == nil { return nil } - ws, err := term.GetWinsize(os.Stdin.Fd()) - if err != nil { - return err - } - return term.SetWinsize(t.console.Fd(), ws) + return t.console.ResizeFrom(console.Current()) } diff --git a/vendor/github.com/opencontainers/runc/update.go b/vendor/github.com/opencontainers/runc/update.go new file mode 100644 index 0000000000000000000000000000000000000000..05dc4b516ba2e991e37e6a9430787beda538ae54 --- /dev/null +++ b/vendor/github.com/opencontainers/runc/update.go @@ -0,0 +1,304 @@ +// +build linux + +package main + +import ( + "encoding/json" + "fmt" + "os" + "strconv" + + "github.com/docker/go-units" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/urfave/cli" +) + +func i64Ptr(i int64) *int64 { return &i } +func u64Ptr(i uint64) *uint64 { return &i } +func u16Ptr(i uint16) *uint16 { return &i } + +var updateCommand = cli.Command{ + Name: "update", + Usage: "update container resource constraints", + ArgsUsage: `<container-id>`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "resources, r", + Value: "", + Usage: `path to the file containing the resources to update or '-' to read from the standard input + +The accepted format is as follow (unchanged values can be omitted): + +{ + "memory": { + "limit": 0, + "reservation": 0, + "swap": 0, + "kernel": 0, + "kernelTCP": 0 + }, + "cpu": { + "shares": 0, + "quota": 0, + "period": 0, + "realtimeRuntime": 0, + "realtimePeriod": 0, + "cpus": "", + "mems": "" + }, + "blockIO": { + "weight": 0 + } +} + +Note: if data is to be read from a file or the standard input, all +other options are ignored. +`, + }, + + cli.IntFlag{ + Name: "blkio-weight", + Usage: "Specifies per cgroup weight, range is from 10 to 1000", + }, + cli.StringFlag{ + Name: "cpu-period", + Usage: "CPU CFS period to be used for hardcapping (in usecs). 0 to use system default", + }, + cli.StringFlag{ + Name: "cpu-quota", + Usage: "CPU CFS hardcap limit (in usecs). Allowed cpu time in a given period", + }, + cli.StringFlag{ + Name: "cpu-share", + Usage: "CPU shares (relative weight vs. other containers)", + }, + cli.StringFlag{ + Name: "cpu-rt-period", + Usage: "CPU realtime period to be used for hardcapping (in usecs). 0 to use system default", + }, + cli.StringFlag{ + Name: "cpu-rt-runtime", + Usage: "CPU realtime hardcap limit (in usecs). Allowed cpu time in a given period", + }, + cli.StringFlag{ + Name: "cpuset-cpus", + Usage: "CPU(s) to use", + }, + cli.StringFlag{ + Name: "cpuset-mems", + Usage: "Memory node(s) to use", + }, + cli.StringFlag{ + Name: "kernel-memory", + Usage: "Kernel memory limit (in bytes)", + }, + cli.StringFlag{ + Name: "kernel-memory-tcp", + Usage: "Kernel memory limit (in bytes) for tcp buffer", + }, + cli.StringFlag{ + Name: "memory", + Usage: "Memory limit (in bytes)", + }, + cli.StringFlag{ + Name: "memory-reservation", + Usage: "Memory reservation or soft_limit (in bytes)", + }, + cli.StringFlag{ + Name: "memory-swap", + Usage: "Total memory usage (memory + swap); set '-1' to enable unlimited swap", + }, + cli.IntFlag{ + Name: "pids-limit", + Usage: "Maximum number of pids allowed in the container", + }, + cli.StringFlag{ + Name: "l3-cache-schema", + Usage: "The string of Intel RDT/CAT L3 cache schema", + }, + cli.StringFlag{ + Name: "mem-bw-schema", + Usage: "The string of Intel RDT/MBA memory bandwidth schema", + }, + }, + Action: func(context *cli.Context) error { + if err := checkArgs(context, 1, exactArgs); err != nil { + return err + } + container, err := getContainer(context) + if err != nil { + return err + } + + r := specs.LinuxResources{ + Memory: &specs.LinuxMemory{ + Limit: i64Ptr(0), + Reservation: i64Ptr(0), + Swap: i64Ptr(0), + Kernel: i64Ptr(0), + KernelTCP: i64Ptr(0), + }, + CPU: &specs.LinuxCPU{ + Shares: u64Ptr(0), + Quota: i64Ptr(0), + Period: u64Ptr(0), + RealtimeRuntime: i64Ptr(0), + RealtimePeriod: u64Ptr(0), + Cpus: "", + Mems: "", + }, + BlockIO: &specs.LinuxBlockIO{ + Weight: u16Ptr(0), + }, + Pids: &specs.LinuxPids{ + Limit: 0, + }, + } + + config := container.Config() + + if in := context.String("resources"); in != "" { + var ( + f *os.File + err error + ) + switch in { + case "-": + f = os.Stdin + default: + f, err = os.Open(in) + if err != nil { + return err + } + } + err = json.NewDecoder(f).Decode(&r) + if err != nil { + return err + } + } else { + if val := context.Int("blkio-weight"); val != 0 { + r.BlockIO.Weight = u16Ptr(uint16(val)) + } + if val := context.String("cpuset-cpus"); val != "" { + r.CPU.Cpus = val + } + if val := context.String("cpuset-mems"); val != "" { + r.CPU.Mems = val + } + + for _, pair := range []struct { + opt string + dest *uint64 + }{ + + {"cpu-period", r.CPU.Period}, + {"cpu-rt-period", r.CPU.RealtimePeriod}, + {"cpu-share", r.CPU.Shares}, + } { + if val := context.String(pair.opt); val != "" { + var err error + *pair.dest, err = strconv.ParseUint(val, 10, 64) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) + } + } + } + for _, pair := range []struct { + opt string + dest *int64 + }{ + + {"cpu-quota", r.CPU.Quota}, + {"cpu-rt-runtime", r.CPU.RealtimeRuntime}, + } { + if val := context.String(pair.opt); val != "" { + var err error + *pair.dest, err = strconv.ParseInt(val, 10, 64) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) + } + } + } + for _, pair := range []struct { + opt string + dest *int64 + }{ + {"memory", r.Memory.Limit}, + {"memory-swap", r.Memory.Swap}, + {"kernel-memory", r.Memory.Kernel}, + {"kernel-memory-tcp", r.Memory.KernelTCP}, + {"memory-reservation", r.Memory.Reservation}, + } { + if val := context.String(pair.opt); val != "" { + var v int64 + + if val != "-1" { + v, err = units.RAMInBytes(val) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", pair.opt, err) + } + } else { + v = -1 + } + *pair.dest = v + } + } + r.Pids.Limit = int64(context.Int("pids-limit")) + } + + // Update the value + config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight + config.Cgroups.Resources.CpuPeriod = *r.CPU.Period + config.Cgroups.Resources.CpuQuota = *r.CPU.Quota + config.Cgroups.Resources.CpuShares = *r.CPU.Shares + config.Cgroups.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod + config.Cgroups.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime + config.Cgroups.Resources.CpusetCpus = r.CPU.Cpus + config.Cgroups.Resources.CpusetMems = r.CPU.Mems + config.Cgroups.Resources.KernelMemory = *r.Memory.Kernel + config.Cgroups.Resources.KernelMemoryTCP = *r.Memory.KernelTCP + config.Cgroups.Resources.Memory = *r.Memory.Limit + config.Cgroups.Resources.MemoryReservation = *r.Memory.Reservation + config.Cgroups.Resources.MemorySwap = *r.Memory.Swap + config.Cgroups.Resources.PidsLimit = r.Pids.Limit + + // Update Intel RDT + l3CacheSchema := context.String("l3-cache-schema") + memBwSchema := context.String("mem-bw-schema") + if l3CacheSchema != "" && !intelrdt.IsCatEnabled() { + return fmt.Errorf("Intel RDT/CAT: l3 cache schema is not enabled") + } + + if memBwSchema != "" && !intelrdt.IsMbaEnabled() { + return fmt.Errorf("Intel RDT/MBA: memory bandwidth schema is not enabled") + } + + if l3CacheSchema != "" || memBwSchema != "" { + // If intelRdt is not specified in original configuration, we just don't + // Apply() to create intelRdt group or attach tasks for this container. + // In update command, we could re-enable through IntelRdtManager.Apply() + // and then update intelrdt constraint. + if config.IntelRdt == nil { + state, err := container.State() + if err != nil { + return err + } + config.IntelRdt = &configs.IntelRdt{} + intelRdtManager := intelrdt.IntelRdtManager{ + Config: &config, + Id: container.ID(), + Path: state.IntelRdtPath, + } + if err := intelRdtManager.Apply(state.InitProcessPid); err != nil { + return err + } + } + config.IntelRdt.L3CacheSchema = l3CacheSchema + config.IntelRdt.MemBwSchema = memBwSchema + } + + return container.Set(config) + }, +} diff --git a/vendor/github.com/opencontainers/runc/utils.go b/vendor/github.com/opencontainers/runc/utils.go index 269fd9d7d9630c46056e555f624dc0fd6053cc51..5165336fba7e9b8aa6246c3e8d113fa1645ec13b 100644 --- a/vendor/github.com/opencontainers/runc/utils.go +++ b/vendor/github.com/opencontainers/runc/utils.go @@ -1,383 +1,94 @@ -// +build linux - package main import ( - "errors" "fmt" "os" - "os/exec" "path/filepath" "strconv" - "syscall" + "strings" + + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/specs/specs-go" + "github.com/urfave/cli" ) -const wildcard = -1 - -var errEmptyID = errors.New("container id cannot be empty") - -var allowedDevices = []*configs.Device{ - // allow mknod for any device - { - Type: 'c', - Major: wildcard, - Minor: wildcard, - Permissions: "m", - Allow: true, - }, - { - Type: 'b', - Major: wildcard, - Minor: wildcard, - Permissions: "m", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/null", - Major: 1, - Minor: 3, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/random", - Major: 1, - Minor: 8, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/full", - Major: 1, - Minor: 7, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/tty", - Major: 5, - Minor: 0, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/zero", - Major: 1, - Minor: 5, - Permissions: "rwm", - Allow: true, - }, - { - Type: 'c', - Path: "/dev/urandom", - Major: 1, - Minor: 9, - Permissions: "rwm", - Allow: true, - }, - { - Path: "/dev/console", - Type: 'c', - Major: 5, - Minor: 1, - Permissions: "rwm", - Allow: true, - }, - // /dev/pts/ - pts namespaces are "coming soon" - { - Path: "", - Type: 'c', - Major: 136, - Minor: wildcard, - Permissions: "rwm", - Allow: true, - }, - { - Path: "", - Type: 'c', - Major: 5, - Minor: 2, - Permissions: "rwm", - Allow: true, - }, - // tuntap - { - Path: "", - Type: 'c', - Major: 10, - Minor: 200, - Permissions: "rwm", - Allow: true, - }, -} - -var ( - maskedPaths = []string{ - "/proc/kcore", - "/proc/latency_stats", - "/proc/timer_stats", - "/proc/sched_debug", - } - readonlyPaths = []string{ - "/proc/asound", - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger", - } +const ( + exactArgs = iota + minArgs + maxArgs ) -var container libcontainer.Container +func checkArgs(context *cli.Context, expected, checkType int) error { + var err error + cmdName := context.Command.Name + switch checkType { + case exactArgs: + if context.NArg() != expected { + err = fmt.Errorf("%s: %q requires exactly %d argument(s)", os.Args[0], cmdName, expected) + } + case minArgs: + if context.NArg() < expected { + err = fmt.Errorf("%s: %q requires a minimum of %d argument(s)", os.Args[0], cmdName, expected) + } + case maxArgs: + if context.NArg() > expected { + err = fmt.Errorf("%s: %q requires a maximum of %d argument(s)", os.Args[0], cmdName, expected) + } + } -func containerPreload(context *cli.Context) error { - c, err := getContainer(context) if err != nil { + fmt.Printf("Incorrect Usage.\n\n") + cli.ShowCommandHelp(context, cmdName) return err } - container = c return nil } -// loadFactory returns the configured factory instance for execing containers. -func loadFactory(context *cli.Context) (libcontainer.Factory, error) { - var ( - debug = "false" - root = context.GlobalString("root") - ) - if context.GlobalBool("debug") { - debug = "true" - } - abs, err := filepath.Abs(root) - if err != nil { - return nil, err - } - logAbs, err := filepath.Abs(context.GlobalString("log")) - if err != nil { - return nil, err - } - return libcontainer.New(abs, libcontainer.Cgroupfs, func(l *libcontainer.LinuxFactory) error { - l.CriuPath = context.GlobalString("criu") - return nil - }, - libcontainer.InitArgs(os.Args[0], - "--log", logAbs, - "--log-format", context.GlobalString("log-format"), - fmt.Sprintf("--debug=%s", debug), - "init"), - ) -} - -// getContainer returns the specified container instance by loading it from state -// with the default factory. -func getContainer(context *cli.Context) (libcontainer.Container, error) { - id := context.Args().First() - if id == "" { - return nil, errEmptyID - } - factory, err := loadFactory(context) - if err != nil { - return nil, err - } - return factory.Load(id) -} - // fatal prints the error's details if it is a libcontainer specific error type // then exits the program with an exit status of 1. func fatal(err error) { // make sure the error is written to the logger logrus.Error(err) - // return proper unix error codes - if exerr, ok := err.(*exec.Error); ok { - switch exerr.Err { - case os.ErrPermission: - fmt.Fprintln(os.Stderr, err) - os.Exit(126) - case exec.ErrNotFound: - fmt.Fprintln(os.Stderr, err) - os.Exit(127) - default: - if os.IsNotExist(exerr.Err) { - fmt.Fprintf(os.Stderr, "exec: %s: %v\n", strconv.Quote(exerr.Name), os.ErrNotExist) - os.Exit(127) - } - } - } fmt.Fprintln(os.Stderr, err) os.Exit(1) } -func fatalf(t string, v ...interface{}) { - fatal(fmt.Errorf(t, v...)) -} - -func getDefaultImagePath(context *cli.Context) string { - cwd, err := os.Getwd() - if err != nil { - panic(err) - } - return filepath.Join(cwd, "checkpoint") -} - -// newProcess returns a new libcontainer Process with the arguments from the -// spec and stdio from the current process. -func newProcess(p specs.Process) (*libcontainer.Process, error) { - lp := &libcontainer.Process{ - Args: p.Args, - Env: p.Env, - // TODO: fix libcontainer's API to better support uid/gid in a typesafe way. - User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), - Cwd: p.Cwd, - Capabilities: p.Capabilities, - Label: p.SelinuxLabel, - NoNewPrivileges: &p.NoNewPrivileges, - AppArmorProfile: p.ApparmorProfile, - } - for _, rlimit := range p.Rlimits { - rl, err := createLibContainerRlimit(rlimit) - if err != nil { - return nil, err - } - lp.Rlimits = append(lp.Rlimits, rl) - } - return lp, nil -} - -func dupStdio(process *libcontainer.Process, rootuid int) error { - process.Stdin = os.Stdin - process.Stdout = os.Stdout - process.Stderr = os.Stderr - for _, fd := range []uintptr{ - os.Stdin.Fd(), - os.Stdout.Fd(), - os.Stderr.Fd(), - } { - if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil { - return err - } - } - return nil -} - -// If systemd is supporting sd_notify protocol, this function will add support -// for sd_notify protocol from within the container. -func setupSdNotify(spec *specs.Spec, notifySocket string) { - spec.Mounts = append(spec.Mounts, specs.Mount{Destination: notifySocket, Type: "bind", Source: notifySocket, Options: []string{"bind"}}) - spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket)) -} - -func destroy(container libcontainer.Container) { - if err := container.Destroy(); err != nil { - logrus.Error(err) - } -} - -// setupIO sets the proper IO on the process depending on the configuration -// If there is a nil error then there must be a non nil tty returned -func setupIO(process *libcontainer.Process, rootuid int, console string, createTTY, detach bool) (*tty, error) { - // detach and createTty will not work unless a console path is passed - // so error out here before changing any terminal settings - if createTTY && detach && console == "" { - return nil, fmt.Errorf("cannot allocate tty if runc will detach") - } - if createTTY { - return createTty(process, rootuid, console) - } - if detach { - if err := dupStdio(process, rootuid); err != nil { +// setupSpec performs initial setup based on the cli.Context for the container +func setupSpec(context *cli.Context) (*specs.Spec, error) { + bundle := context.String("bundle") + if bundle != "" { + if err := os.Chdir(bundle); err != nil { return nil, err } - return &tty{}, nil - } - return createStdioPipes(process, rootuid) -} - -func createPidFile(path string, process *libcontainer.Process) error { - pid, err := process.Pid() - if err != nil { - return err - } - f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) - if err != nil { - return err - } - defer f.Close() - _, err = fmt.Fprintf(f, "%d", pid) - return err -} - -func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcontainer.Container, error) { - config, err := createLibcontainerConfig(id, spec) - if err != nil { - return nil, err - } - - if _, err := os.Stat(config.Rootfs); err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("rootfs (%q) does not exist", config.Rootfs) - } - return nil, err } - - factory, err := loadFactory(context) + spec, err := loadSpec(specConfig) if err != nil { return nil, err } - return factory.Create(id, config) + return spec, nil } -// runProcess will create a new process in the specified container -// by executing the process specified in the 'config'. -func runProcess(container libcontainer.Container, config *specs.Process, listenFDs []*os.File, console string, pidFile string, detach bool) (int, error) { - process, err := newProcess(*config) - if err != nil { - return -1, err - } - - // Add extra file descriptors if needed - if len(listenFDs) > 0 { - process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(listenFDs)), "LISTEN_PID=1") - process.ExtraFiles = append(process.ExtraFiles, listenFDs...) +func revisePidFile(context *cli.Context) error { + pidFile := context.String("pid-file") + if pidFile == "" { + return nil } - rootuid, err := container.Config().HostUID() + // convert pid-file to an absolute path so we can write to the right + // file after chdir to bundle + pidFile, err := filepath.Abs(pidFile) if err != nil { - return -1, err + return err } + return context.Set("pid-file", pidFile) +} - tty, err := setupIO(process, rootuid, console, config.Terminal, detach) - if err != nil { - return -1, err - } - defer tty.Close() - handler := newSignalHandler(tty) - defer handler.Close() - if err := container.Start(process); err != nil { - return -1, err - } - if err := tty.ClosePostStart(); err != nil { - return -1, err - } - if pidFile != "" { - if err := createPidFile(pidFile, process); err != nil { - process.Signal(syscall.SIGKILL) - process.Wait() - return -1, err - } - } - if detach { - return 0, nil +// parseBoolOrAuto returns (nil, nil) if s is empty or "auto" +func parseBoolOrAuto(s string) (*bool, error) { + if s == "" || strings.ToLower(s) == "auto" { + return nil, nil } - return handler.forward(process) + b, err := strconv.ParseBool(s) + return &b, err } diff --git a/vendor/github.com/opencontainers/runc/utils_linux.go b/vendor/github.com/opencontainers/runc/utils_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..a37b1c3dfa4269baf1b27f6b27837a817dd8caca --- /dev/null +++ b/vendor/github.com/opencontainers/runc/utils_linux.go @@ -0,0 +1,439 @@ +// +build linux + +package main + +import ( + "errors" + "fmt" + "net" + "os" + "os/exec" + "path/filepath" + "strconv" + + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/cgroups/systemd" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/specconv" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/coreos/go-systemd/activation" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + "golang.org/x/sys/unix" +) + +var errEmptyID = errors.New("container id cannot be empty") + +// loadFactory returns the configured factory instance for execing containers. +func loadFactory(context *cli.Context) (libcontainer.Factory, error) { + root := context.GlobalString("root") + abs, err := filepath.Abs(root) + if err != nil { + return nil, err + } + + // We default to cgroupfs, and can only use systemd if the system is a + // systemd box. + cgroupManager := libcontainer.Cgroupfs + rootlessCg, err := shouldUseRootlessCgroupManager(context) + if err != nil { + return nil, err + } + if rootlessCg { + cgroupManager = libcontainer.RootlessCgroupfs + } + if context.GlobalBool("systemd-cgroup") { + if systemd.UseSystemd() { + cgroupManager = libcontainer.SystemdCgroups + } else { + return nil, fmt.Errorf("systemd cgroup flag passed, but systemd support for managing cgroups is not available") + } + } + + intelRdtManager := libcontainer.IntelRdtFs + if !intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() { + intelRdtManager = nil + } + + // We resolve the paths for {newuidmap,newgidmap} from the context of runc, + // to avoid doing a path lookup in the nsexec context. TODO: The binary + // names are not currently configurable. + newuidmap, err := exec.LookPath("newuidmap") + if err != nil { + newuidmap = "" + } + newgidmap, err := exec.LookPath("newgidmap") + if err != nil { + newgidmap = "" + } + + return libcontainer.New(abs, cgroupManager, intelRdtManager, + libcontainer.CriuPath(context.GlobalString("criu")), + libcontainer.NewuidmapPath(newuidmap), + libcontainer.NewgidmapPath(newgidmap)) +} + +// getContainer returns the specified container instance by loading it from state +// with the default factory. +func getContainer(context *cli.Context) (libcontainer.Container, error) { + id := context.Args().First() + if id == "" { + return nil, errEmptyID + } + factory, err := loadFactory(context) + if err != nil { + return nil, err + } + return factory.Load(id) +} + +func fatalf(t string, v ...interface{}) { + fatal(fmt.Errorf(t, v...)) +} + +func getDefaultImagePath(context *cli.Context) string { + cwd, err := os.Getwd() + if err != nil { + panic(err) + } + return filepath.Join(cwd, "checkpoint") +} + +// newProcess returns a new libcontainer Process with the arguments from the +// spec and stdio from the current process. +func newProcess(p specs.Process, init bool) (*libcontainer.Process, error) { + lp := &libcontainer.Process{ + Args: p.Args, + Env: p.Env, + // TODO: fix libcontainer's API to better support uid/gid in a typesafe way. + User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), + Cwd: p.Cwd, + Label: p.SelinuxLabel, + NoNewPrivileges: &p.NoNewPrivileges, + AppArmorProfile: p.ApparmorProfile, + Init: init, + } + + if p.ConsoleSize != nil { + lp.ConsoleWidth = uint16(p.ConsoleSize.Width) + lp.ConsoleHeight = uint16(p.ConsoleSize.Height) + } + + if p.Capabilities != nil { + lp.Capabilities = &configs.Capabilities{} + lp.Capabilities.Bounding = p.Capabilities.Bounding + lp.Capabilities.Effective = p.Capabilities.Effective + lp.Capabilities.Inheritable = p.Capabilities.Inheritable + lp.Capabilities.Permitted = p.Capabilities.Permitted + lp.Capabilities.Ambient = p.Capabilities.Ambient + } + for _, gid := range p.User.AdditionalGids { + lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10)) + } + for _, rlimit := range p.Rlimits { + rl, err := createLibContainerRlimit(rlimit) + if err != nil { + return nil, err + } + lp.Rlimits = append(lp.Rlimits, rl) + } + return lp, nil +} + +func destroy(container libcontainer.Container) { + if err := container.Destroy(); err != nil { + logrus.Error(err) + } +} + +// setupIO modifies the given process config according to the options. +func setupIO(process *libcontainer.Process, rootuid, rootgid int, createTTY, detach bool, sockpath string) (*tty, error) { + if createTTY { + process.Stdin = nil + process.Stdout = nil + process.Stderr = nil + t := &tty{} + if !detach { + parent, child, err := utils.NewSockPair("console") + if err != nil { + return nil, err + } + process.ConsoleSocket = child + t.postStart = append(t.postStart, parent, child) + t.consoleC = make(chan error, 1) + go func() { + if err := t.recvtty(process, parent); err != nil { + t.consoleC <- err + } + t.consoleC <- nil + }() + } else { + // the caller of runc will handle receiving the console master + conn, err := net.Dial("unix", sockpath) + if err != nil { + return nil, err + } + uc, ok := conn.(*net.UnixConn) + if !ok { + return nil, fmt.Errorf("casting to UnixConn failed") + } + t.postStart = append(t.postStart, uc) + socket, err := uc.File() + if err != nil { + return nil, err + } + t.postStart = append(t.postStart, socket) + process.ConsoleSocket = socket + } + return t, nil + } + // when runc will detach the caller provides the stdio to runc via runc's 0,1,2 + // and the container's process inherits runc's stdio. + if detach { + if err := inheritStdio(process); err != nil { + return nil, err + } + return &tty{}, nil + } + return setupProcessPipes(process, rootuid, rootgid) +} + +// createPidFile creates a file with the processes pid inside it atomically +// it creates a temp file with the paths filename + '.' infront of it +// then renames the file +func createPidFile(path string, process *libcontainer.Process) error { + pid, err := process.Pid() + if err != nil { + return err + } + var ( + tmpDir = filepath.Dir(path) + tmpName = filepath.Join(tmpDir, fmt.Sprintf(".%s", filepath.Base(path))) + ) + f, err := os.OpenFile(tmpName, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666) + if err != nil { + return err + } + _, err = fmt.Fprintf(f, "%d", pid) + f.Close() + if err != nil { + return err + } + return os.Rename(tmpName, path) +} + +func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcontainer.Container, error) { + rootlessCg, err := shouldUseRootlessCgroupManager(context) + if err != nil { + return nil, err + } + config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{ + CgroupName: id, + UseSystemdCgroup: context.GlobalBool("systemd-cgroup"), + NoPivotRoot: context.Bool("no-pivot"), + NoNewKeyring: context.Bool("no-new-keyring"), + Spec: spec, + RootlessEUID: os.Geteuid() != 0, + RootlessCgroups: rootlessCg, + }) + if err != nil { + return nil, err + } + + factory, err := loadFactory(context) + if err != nil { + return nil, err + } + return factory.Create(id, config) +} + +type runner struct { + init bool + enableSubreaper bool + shouldDestroy bool + detach bool + listenFDs []*os.File + preserveFDs int + pidFile string + consoleSocket string + container libcontainer.Container + action CtAct + notifySocket *notifySocket + criuOpts *libcontainer.CriuOpts +} + +func (r *runner) run(config *specs.Process) (int, error) { + if err := r.checkTerminal(config); err != nil { + r.destroy() + return -1, err + } + process, err := newProcess(*config, r.init) + if err != nil { + r.destroy() + return -1, err + } + if len(r.listenFDs) > 0 { + process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(r.listenFDs)), "LISTEN_PID=1") + process.ExtraFiles = append(process.ExtraFiles, r.listenFDs...) + } + baseFd := 3 + len(process.ExtraFiles) + for i := baseFd; i < baseFd+r.preserveFDs; i++ { + process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "PreserveFD:"+strconv.Itoa(i))) + } + rootuid, err := r.container.Config().HostRootUID() + if err != nil { + r.destroy() + return -1, err + } + rootgid, err := r.container.Config().HostRootGID() + if err != nil { + r.destroy() + return -1, err + } + var ( + detach = r.detach || (r.action == CT_ACT_CREATE) + ) + // Setting up IO is a two stage process. We need to modify process to deal + // with detaching containers, and then we get a tty after the container has + // started. + handler := newSignalHandler(r.enableSubreaper, r.notifySocket) + tty, err := setupIO(process, rootuid, rootgid, config.Terminal, detach, r.consoleSocket) + if err != nil { + r.destroy() + return -1, err + } + defer tty.Close() + + switch r.action { + case CT_ACT_CREATE: + err = r.container.Start(process) + case CT_ACT_RESTORE: + err = r.container.Restore(process, r.criuOpts) + case CT_ACT_RUN: + err = r.container.Run(process) + default: + panic("Unknown action") + } + if err != nil { + r.destroy() + return -1, err + } + if err := tty.waitConsole(); err != nil { + r.terminate(process) + r.destroy() + return -1, err + } + if err = tty.ClosePostStart(); err != nil { + r.terminate(process) + r.destroy() + return -1, err + } + if r.pidFile != "" { + if err = createPidFile(r.pidFile, process); err != nil { + r.terminate(process) + r.destroy() + return -1, err + } + } + status, err := handler.forward(process, tty, detach) + if err != nil { + r.terminate(process) + } + if detach { + return 0, nil + } + r.destroy() + return status, err +} + +func (r *runner) destroy() { + if r.shouldDestroy { + destroy(r.container) + } +} + +func (r *runner) terminate(p *libcontainer.Process) { + _ = p.Signal(unix.SIGKILL) + _, _ = p.Wait() +} + +func (r *runner) checkTerminal(config *specs.Process) error { + detach := r.detach || (r.action == CT_ACT_CREATE) + // Check command-line for sanity. + if detach && config.Terminal && r.consoleSocket == "" { + return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket") + } + if (!detach || !config.Terminal) && r.consoleSocket != "" { + return fmt.Errorf("cannot use console socket if runc will not detach or allocate tty") + } + return nil +} + +func validateProcessSpec(spec *specs.Process) error { + if spec.Cwd == "" { + return fmt.Errorf("Cwd property must not be empty") + } + if !filepath.IsAbs(spec.Cwd) { + return fmt.Errorf("Cwd must be an absolute path") + } + if len(spec.Args) == 0 { + return fmt.Errorf("args must not be empty") + } + return nil +} + +type CtAct uint8 + +const ( + CT_ACT_CREATE CtAct = iota + 1 + CT_ACT_RUN + CT_ACT_RESTORE +) + +func startContainer(context *cli.Context, spec *specs.Spec, action CtAct, criuOpts *libcontainer.CriuOpts) (int, error) { + id := context.Args().First() + if id == "" { + return -1, errEmptyID + } + + notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id) + if notifySocket != nil { + notifySocket.setupSpec(context, spec) + } + + container, err := createContainer(context, id, spec) + if err != nil { + return -1, err + } + + if notifySocket != nil { + err := notifySocket.setupSocket() + if err != nil { + return -1, err + } + } + + // Support on-demand socket activation by passing file descriptors into the container init process. + listenFDs := []*os.File{} + if os.Getenv("LISTEN_FDS") != "" { + listenFDs = activation.Files(false) + } + r := &runner{ + enableSubreaper: !context.Bool("no-subreaper"), + shouldDestroy: true, + container: container, + listenFDs: listenFDs, + notifySocket: notifySocket, + consoleSocket: context.String("console-socket"), + detach: context.Bool("detach"), + pidFile: context.String("pid-file"), + preserveFDs: context.Int("preserve-fds"), + action: action, + criuOpts: criuOpts, + init: true, + } + return r.run(spec.Process) +}