mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-12-19 07:00:17 +01:00
33f99c4fc1
Uses godep to vendor dependencies. Godeps is not necessary during build, golang's new vendor support is used instead.
258 lines
5.8 KiB
Go
258 lines
5.8 KiB
Go
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
|
|
}
|