diff --git a/hack/vendor.sh b/hack/vendor.sh index b066ae29fe..b3783defcf 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -65,7 +65,7 @@ clone git github.com/opencontainers/specs 93ca97e83ca7fb4fba6d9e30d5470f99ddc02d clone git github.com/seccomp/libseccomp-golang 1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1 # libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) clone git github.com/coreos/go-systemd v4 -clone git github.com/godbus/dbus v3 +clone git github.com/godbus/dbus v4.0.0 clone git github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 clone git github.com/golang/protobuf 68415e7123da32b07eab49c96d2c4d6158360e9b diff --git a/vendor/src/github.com/godbus/dbus/conn.go b/vendor/src/github.com/godbus/dbus/conn.go index a4f5394010..9aa2e12809 100644 --- a/vendor/src/github.com/godbus/dbus/conn.go +++ b/vendor/src/github.com/godbus/dbus/conn.go @@ -16,6 +16,7 @@ var ( systemBusLck sync.Mutex sessionBus *Conn sessionBusLck sync.Mutex + sessionEnvLck sync.Mutex ) // ErrClosed is the error returned by calls on a closed connection. @@ -46,7 +47,7 @@ type Conn struct { calls map[uint32]*Call callsLck sync.RWMutex - handlers map[ObjectPath]map[string]exportWithMapping + handlers map[ObjectPath]map[string]exportedObj handlersLck sync.RWMutex out chan *Message @@ -91,6 +92,8 @@ func SessionBus() (conn *Conn, err error) { // SessionBusPrivate returns a new private connection to the session bus. func SessionBusPrivate() (*Conn, error) { + sessionEnvLck.Lock() + defer sessionEnvLck.Unlock() address := os.Getenv("DBUS_SESSION_BUS_ADDRESS") if address != "" && address != "autolaunch:" { return Dial(address) @@ -157,7 +160,7 @@ func newConn(tr transport) (*Conn, error) { conn.transport = tr conn.calls = make(map[uint32]*Call) conn.out = make(chan *Message, 10) - conn.handlers = make(map[ObjectPath]map[string]exportWithMapping) + conn.handlers = make(map[ObjectPath]map[string]exportedObj) conn.nextSerial = 1 conn.serialUsed = map[uint32]bool{0: true} conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") @@ -499,9 +502,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { // 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. +// Multiple of these channels can be registered at the same time. // // These channels are "overwritten" by Eavesdrop; i.e., if there currently is a // channel for eavesdropped messages, this channel receives all signals, and @@ -512,6 +513,19 @@ func (conn *Conn) Signal(ch chan<- *Signal) { conn.signalsLck.Unlock() } +// RemoveSignal removes the given channel from the list of the registered channels. +func (conn *Conn) RemoveSignal(ch chan<- *Signal) { + conn.signalsLck.Lock() + for i := len(conn.signals) - 1; i >= 0; i-- { + if ch == conn.signals[i] { + copy(conn.signals[i:], conn.signals[i+1:]) + conn.signals[len(conn.signals)-1] = nil + conn.signals = conn.signals[:len(conn.signals)-1] + } + } + 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 @@ -610,16 +624,11 @@ func dereferenceAll(vs []interface{}) []interface{} { // 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 "" + for _, keyEqualsValue := range strings.Split(s, ",") { + keyValue := strings.SplitN(keyEqualsValue, "=", 2) + if len(keyValue) == 2 && keyValue[0] == key { + return keyValue[1] + } } - 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] + return "" } diff --git a/vendor/src/github.com/godbus/dbus/conn_other.go b/vendor/src/github.com/godbus/dbus/conn_other.go index f74b8758d4..289e8c5d2b 100644 --- a/vendor/src/github.com/godbus/dbus/conn_other.go +++ b/vendor/src/github.com/godbus/dbus/conn_other.go @@ -5,6 +5,7 @@ package dbus import ( "bytes" "errors" + "os" "os/exec" ) @@ -23,5 +24,8 @@ func sessionBusPlatform() (*Conn, error) { return nil, errors.New("dbus: couldn't determine address of session bus") } - return Dial(string(b[i+1 : j])) + env, addr := string(b[0:i]), string(b[i+1:j]) + os.Setenv(env, addr) + + return Dial(addr) } diff --git a/vendor/src/github.com/godbus/dbus/export.go b/vendor/src/github.com/godbus/dbus/export.go index c6440a7416..6c33522026 100644 --- a/vendor/src/github.com/godbus/dbus/export.go +++ b/vendor/src/github.com/godbus/dbus/export.go @@ -1,6 +1,7 @@ package dbus import ( + "bytes" "errors" "fmt" "reflect" @@ -22,67 +23,60 @@ var ( } ) -// 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 +// exportedObj represents an exported object. It stores a precomputed +// method table that represents the methods exported on the bus. +type exportedObj struct { + methods map[string]reflect.Value // Whether or not this export is for the entire subtree includeSubtree bool } +func (obj exportedObj) Method(name string) (reflect.Value, bool) { + out, exists := obj.methods[name] + return out, exists +} + // 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{} +func computeMethodName(name string, mapping map[string]string) string { + newname, ok := mapping[name] + if ok { + name = newname } + return name +} - // 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{} - } +func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value { + if in == nil { + return nil + } + methods := make(map[string]reflect.Value) + val := reflect.ValueOf(in) + typ := val.Type() + for i := 0; i < typ.NumMethod(); i++ { + methtype := typ.Method(i) + method := val.Method(i) + t := method.Type() + // only track valid methods must return *Error as last arg + // and must be exported + if t.NumOut() == 0 || + t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) || + methtype.PkgPath != "" { + continue } + // map names while building table + methods[computeMethodName(methtype.Name, mapping)] = method } - - 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 + return methods } // 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) { +func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportedObj, bool) { conn.handlersLck.RLock() defer conn.handlersLck.RUnlock() @@ -93,10 +87,10 @@ func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, // If handlers weren't found for this exact path, look for a matching subtree // registration - handlers = make(map[string]exportWithMapping) + handlers = make(map[string]exportedObj) path = path[:strings.LastIndex(string(path), "/")] for len(path) > 0 { - var subtreeHandlers map[string]exportWithMapping + var subtreeHandlers map[string]exportedObj subtreeHandlers, ok = conn.handlers[path] if ok { for iface, handler := range subtreeHandlers { @@ -133,6 +127,28 @@ func (conn *Conn) handleCall(msg *Message) { conn.sendError(errmsgUnknownMethod, sender, serial) } return + } else if ifaceName == "org.freedesktop.DBus.Introspectable" && name == "Introspect" { + if _, ok := conn.handlers[path]; !ok { + subpath := make(map[string]struct{}) + var xml bytes.Buffer + xml.WriteString("") + for h, _ := range conn.handlers { + p := string(path) + if p != "/" { + p += "/" + } + if strings.HasPrefix(string(h), p) { + node_name := strings.Split(string(h[len(p):]), "/")[0] + subpath[node_name] = struct{}{} + } + } + for s, _ := range subpath { + xml.WriteString("\n\t") + } + xml.WriteString("\n") + conn.sendReply(sender, serial, xml.String()) + return + } } if len(name) == 0 { conn.sendError(errmsgUnknownMethod, sender, serial) @@ -146,19 +162,20 @@ func (conn *Conn) handleCall(msg *Message) { } var m reflect.Value + var exists bool if hasIface { iface := handlers[ifaceName] - m = exportedMethod(iface, name) + m, exists = iface.Method(name) } else { for _, v := range handlers { - m = exportedMethod(v, name) - if m.IsValid() { + m, exists = v.Method(name) + if exists { break } } } - if !m.IsValid() { + if !exists { conn.sendError(errmsgUnknownMethod, sender, serial) return } @@ -303,7 +320,7 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { // 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) + return conn.export(getMethods(v, mapping), path, iface, false) } // ExportSubtree works exactly like Export but registers the given value for @@ -326,11 +343,48 @@ func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) er // 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) + return conn.export(getMethods(v, mapping), path, iface, true) +} + +// ExportMethodTable like Export registers the given methods as an object +// on the message bus. Unlike Export the it uses a method table to define +// the object instead of a native go object. +// +// The method table is a map from method name to function closure +// representing the method. This allows an object exported on the bus to not +// necessarily be a native go object. It can be useful for generating exposed +// methods on the fly. +// +// Any non-function objects in the method table are ignored. +func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error { + return conn.exportMethodTable(methods, path, iface, false) +} + +// Like ExportSubtree, but with the same caveats as ExportMethodTable. +func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error { + return conn.exportMethodTable(methods, path, iface, true) +} + +func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error { + out := make(map[string]reflect.Value) + for name, method := range methods { + rval := reflect.ValueOf(method) + if rval.Kind() != reflect.Func { + continue + } + t := rval.Type() + // only track valid methods must return *Error as last arg + if t.NumOut() == 0 || + t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) { + continue + } + out[name] = rval + } + return conn.export(out, path, iface, includeSubtree) } // 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 { +func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error { if !path.IsValid() { return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) } @@ -339,7 +393,7 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O defer conn.handlersLck.Unlock() // Remove a previous export if the interface is nil - if v == nil { + if methods == nil { if _, ok := conn.handlers[path]; ok { delete(conn.handlers[path], iface) if len(conn.handlers[path]) == 0 { @@ -353,11 +407,14 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O // 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) + conn.handlers[path] = make(map[string]exportedObj) } // Finally, save this handler - conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree} + conn.handlers[path][iface] = exportedObj{ + methods: methods, + includeSubtree: includeSubtree, + } return nil } diff --git a/vendor/src/github.com/godbus/dbus/message.go b/vendor/src/github.com/godbus/dbus/message.go index 075d6e38ba..6a925367eb 100644 --- a/vendor/src/github.com/godbus/dbus/message.go +++ b/vendor/src/github.com/godbus/dbus/message.go @@ -22,6 +22,13 @@ const ( // FlagNoAutoStart signals that the message bus should not automatically // start an application when handling this message. FlagNoAutoStart + // FlagAllowInteractiveAuthorization may be set on a method call + // message to inform the receiving side that the caller is prepared + // to wait for interactive authorization, which might take a + // considerable time to complete. For instance, if this flag is set, + // it would be appropriate to query the user for passwords or + // confirmation via Polkit or a similar framework. + FlagAllowInteractiveAuthorization ) // Type represents the possible types of a D-Bus message. @@ -248,7 +255,7 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { // 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 { + if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected|FlagAllowInteractiveAuthorization) != 0 { return InvalidMessageError("invalid flags") } if msg.Type == 0 || msg.Type >= typeMax { diff --git a/vendor/src/github.com/godbus/dbus/object.go b/vendor/src/github.com/godbus/dbus/object.go index 7ef45da4c8..9573b7095a 100644 --- a/vendor/src/github.com/godbus/dbus/object.go +++ b/vendor/src/github.com/godbus/dbus/object.go @@ -27,6 +27,16 @@ func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { return <-o.Go(method, flags, make(chan *Call, 1), args...).Done } +// AddMatchSignal subscribes BusObject to signals from specified interface and +// method (member). +func (o *Object) AddMatchSignal(iface, member string) *Call { + return o.Call( + "org.freedesktop.DBus.AddMatch", + 0, + "type='signal',interface='"+iface+"',member='"+member+"'", + ) +} + // 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 diff --git a/vendor/src/github.com/godbus/dbus/transport_tcp.go b/vendor/src/github.com/godbus/dbus/transport_tcp.go new file mode 100644 index 0000000000..dd1c8e59c5 --- /dev/null +++ b/vendor/src/github.com/godbus/dbus/transport_tcp.go @@ -0,0 +1,43 @@ +//+build !windows + +package dbus + +import ( + "errors" + "net" +) + +func init() { + transports["tcp"] = newTcpTransport +} + +func tcpFamily(keys string) (string, error) { + switch getKey(keys, "family") { + case "": + return "tcp", nil + case "ipv4": + return "tcp4", nil + case "ipv6": + return "tcp6", nil + default: + return "", errors.New("dbus: invalid tcp family (must be ipv4 or ipv6)") + } +} + +func newTcpTransport(keys string) (transport, error) { + host := getKey(keys, "host") + port := getKey(keys, "port") + if host == "" || port == "" { + return nil, errors.New("dbus: unsupported address (must set host and port)") + } + + protocol, err := tcpFamily(keys) + if err != nil { + return nil, err + } + socket, err := net.Dial(protocol, net.JoinHostPort(host, port)) + if err != nil { + return nil, err + } + return NewConn(socket) +} diff --git a/vendor/src/github.com/godbus/dbus/transport_unix.go b/vendor/src/github.com/godbus/dbus/transport_unix.go index 3fafeabb15..a1d00cbc12 100644 --- a/vendor/src/github.com/godbus/dbus/transport_unix.go +++ b/vendor/src/github.com/godbus/dbus/transport_unix.go @@ -1,4 +1,4 @@ -//+build !windows +//+build !windows,!solaris package dbus