summaryrefslogtreecommitdiff
path: root/vendor/github.com/lufia/plan9stats/host.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/lufia/plan9stats/host.go')
-rw-r--r--vendor/github.com/lufia/plan9stats/host.go303
1 files changed, 303 insertions, 0 deletions
diff --git a/vendor/github.com/lufia/plan9stats/host.go b/vendor/github.com/lufia/plan9stats/host.go
new file mode 100644
index 0000000..957e903
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/host.go
@@ -0,0 +1,303 @@
+package stats
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+var (
+ delim = []byte{' '}
+)
+
+// Host represents host status.
+type Host struct {
+ Sysname string
+ Storages []*Storage
+ Interfaces []*Interface
+}
+
+// MemStats represents the memory statistics.
+type MemStats struct {
+ Total int64 // total memory in byte
+ PageSize int64 // a page size in byte
+ KernelPages int64
+ UserPages Gauge
+ SwapPages Gauge
+
+ Malloced Gauge // kernel malloced data in byte
+ Graphics Gauge // kernel graphics data in byte
+}
+
+// Gauge is used/available gauge.
+type Gauge struct {
+ Used int64
+ Avail int64
+}
+
+func (g Gauge) Free() int64 {
+ return g.Avail - g.Used
+}
+
+// ReadMemStats reads memory statistics from /dev/swap.
+func ReadMemStats(ctx context.Context, opts ...Option) (*MemStats, error) {
+ cfg := newConfig(opts...)
+ swap := filepath.Join(cfg.rootdir, "/dev/swap")
+ f, err := os.Open(swap)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ var stat MemStats
+ m := map[string]interface{}{
+ "memory": &stat.Total,
+ "pagesize": &stat.PageSize,
+ "kernel": &stat.KernelPages,
+ "user": &stat.UserPages,
+ "swap": &stat.SwapPages,
+ "kernel malloc": &stat.Malloced,
+ "kernel draw": &stat.Graphics,
+ }
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ fields := bytes.SplitN(scanner.Bytes(), delim, 2)
+ if len(fields) < 2 {
+ continue
+ }
+ switch key := string(fields[1]); key {
+ case "memory", "pagesize", "kernel":
+ v := m[key].(*int64)
+ n, err := strconv.ParseInt(string(fields[0]), 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ *v = n
+ case "user", "swap", "kernel malloc", "kernel draw":
+ v := m[key].(*Gauge)
+ if err := parseGauge(string(fields[0]), v); err != nil {
+ return nil, err
+ }
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+ return &stat, nil
+}
+
+func parseGauge(s string, r *Gauge) error {
+ a := strings.SplitN(s, "/", 2)
+ if len(a) != 2 {
+ return fmt.Errorf("can't parse ratio: %s", s)
+ }
+ var p intParser
+ u := p.ParseInt64(a[0], 10)
+ n := p.ParseInt64(a[1], 10)
+ if err := p.Err(); err != nil {
+ return err
+ }
+ r.Used = u
+ r.Avail = n
+ return nil
+}
+
+type Storage struct {
+ Name string
+ Model string
+ Capacity int64
+}
+
+type Interface struct {
+ Name string
+ Addr string
+}
+
+const (
+ numEther = 8 // see ether(3)
+ numIpifc = 16 // see ip(3)
+)
+
+// ReadInterfaces reads network interfaces from etherN.
+func ReadInterfaces(ctx context.Context, opts ...Option) ([]*Interface, error) {
+ cfg := newConfig(opts...)
+ var a []*Interface
+ for i := 0; i < numEther; i++ {
+ p, err := readInterface(cfg.rootdir, i)
+ if os.IsNotExist(err) {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ a = append(a, p)
+ }
+ return a, nil
+}
+
+func readInterface(netroot string, i int) (*Interface, error) {
+ ether := fmt.Sprintf("ether%d", i)
+ dir := filepath.Join(netroot, ether)
+ info, err := os.Stat(dir)
+ if err != nil {
+ return nil, err
+ }
+ if !info.IsDir() {
+ return nil, fmt.Errorf("%s: is not directory", dir)
+ }
+
+ addr, err := ioutil.ReadFile(filepath.Join(dir, "addr"))
+ if err != nil {
+ return nil, err
+ }
+ return &Interface{
+ Name: ether,
+ Addr: string(addr),
+ }, nil
+}
+
+var (
+ netdirs = []string{"/net", "/net.alt"}
+)
+
+// ReadHost reads host status.
+func ReadHost(ctx context.Context, opts ...Option) (*Host, error) {
+ cfg := newConfig(opts...)
+ var h Host
+ name, err := readSysname(cfg.rootdir)
+ if err != nil {
+ return nil, err
+ }
+ h.Sysname = name
+
+ a, err := readStorages(cfg.rootdir)
+ if err != nil {
+ return nil, err
+ }
+ h.Storages = a
+
+ for _, s := range netdirs {
+ netroot := filepath.Join(cfg.rootdir, s)
+ ifaces, err := ReadInterfaces(ctx, WithRootDir(netroot))
+ if err != nil {
+ return nil, err
+ }
+ h.Interfaces = append(h.Interfaces, ifaces...)
+ }
+ return &h, nil
+}
+
+func readSysname(rootdir string) (string, error) {
+ file := filepath.Join(rootdir, "/dev/sysname")
+ b, err := ioutil.ReadFile(file)
+ if err != nil {
+ return "", err
+ }
+ return string(bytes.TrimSpace(b)), nil
+}
+
+func readStorages(rootdir string) ([]*Storage, error) {
+ sdctl := filepath.Join(rootdir, "/dev/sdctl")
+ f, err := os.Open(sdctl)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ var a []*Storage
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ fields := bytes.Split(scanner.Bytes(), delim)
+ if len(fields) == 0 {
+ continue
+ }
+ exp := string(fields[0]) + "*"
+ if !strings.HasPrefix(exp, "sd") {
+ continue
+ }
+ dir := filepath.Join(rootdir, "/dev", exp)
+ m, err := filepath.Glob(dir)
+ if err != nil {
+ return nil, err
+ }
+ for _, dir := range m {
+ s, err := readStorage(dir)
+ if err != nil {
+ return nil, err
+ }
+ a = append(a, s)
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+ return a, nil
+}
+
+func readStorage(dir string) (*Storage, error) {
+ ctl := filepath.Join(dir, "ctl")
+ f, err := os.Open(ctl)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ var s Storage
+ s.Name = filepath.Base(dir)
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Bytes()
+ switch {
+ case bytes.HasPrefix(line, []byte("inquiry")):
+ s.Model = string(bytes.TrimSpace(line[7:]))
+ case bytes.HasPrefix(line, []byte("geometry")):
+ fields := bytes.Split(line, delim)
+ if len(fields) < 3 {
+ continue
+ }
+ var p intParser
+ sec := p.ParseInt64(string(fields[1]), 10)
+ size := p.ParseInt64(string(fields[2]), 10)
+ if err := p.Err(); err != nil {
+ return nil, err
+ }
+ s.Capacity = sec * size
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+ return &s, nil
+}
+
+type IPStats struct {
+ ID int // number of interface in ipifc dir
+ Device string // associated physical device
+ MTU int // max transfer unit
+ Sendra6 uint8 // on == send router adv
+ Recvra6 uint8 // on == recv router adv
+
+ Pktin int64 // packets read
+ Pktout int64 // packets written
+ Errin int64 // read errors
+ Errout int64 // write errors
+}
+
+type Iplifc struct {
+ IP net.IP
+ Mask net.IPMask
+ Net net.IP // ip & mask
+ PerfLifetime int64 // preferred lifetime
+ ValidLifetime int64 // valid lifetime
+}
+
+type Ipv6rp struct {
+ // TODO(lufia): see ip(2)
+}