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