parseSockstat reads the contents of a sockstat file and parses a NetSockstat.
(r io.Reader)
| 77 | |
| 78 | // parseSockstat reads the contents of a sockstat file and parses a NetSockstat. |
| 79 | func parseSockstat(r io.Reader) (*NetSockstat, error) { |
| 80 | var stat NetSockstat |
| 81 | s := bufio.NewScanner(r) |
| 82 | for s.Scan() { |
| 83 | // Expect a minimum of a protocol and one key/value pair. |
| 84 | fields := strings.Split(s.Text(), " ") |
| 85 | if len(fields) < 3 { |
| 86 | return nil, fmt.Errorf("%w: Malformed sockstat line: %q", ErrFileParse, s.Text()) |
| 87 | } |
| 88 | |
| 89 | // The remaining fields are key/value pairs. |
| 90 | kvs, err := parseSockstatKVs(fields[1:]) |
| 91 | if err != nil { |
| 92 | return nil, fmt.Errorf("%w: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err) |
| 93 | } |
| 94 | |
| 95 | // The first field is the protocol. We must trim its colon suffix. |
| 96 | proto := strings.TrimSuffix(fields[0], ":") |
| 97 | switch proto { |
| 98 | case "sockets": |
| 99 | // Special case: IPv4 has a sockets "used" key/value pair that we |
| 100 | // embed at the top level of the structure. |
| 101 | used := kvs["used"] |
| 102 | stat.Used = &used |
| 103 | default: |
| 104 | // Parse all other lines as individual protocols. |
| 105 | nsp := parseSockstatProtocol(kvs) |
| 106 | nsp.Protocol = proto |
| 107 | stat.Protocols = append(stat.Protocols, nsp) |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | if err := s.Err(); err != nil { |
| 112 | return nil, err |
| 113 | } |
| 114 | |
| 115 | return &stat, nil |
| 116 | } |
| 117 | |
| 118 | // parseSockstatKVs parses a string slice into a map of key/value pairs. |
| 119 | func parseSockstatKVs(kvs []string) (map[string]int, error) { |