package hostcollect import ( "io" "os" "strconv" "strings" ) // readLimited reads at most limit bytes from path. Every /proc file the collector // touches is small, but /proc is a kernel interface and a bounded read keeps a // pathological or hostile file from becoming an unbounded allocation. func readLimited(path string, limit int64) ([]byte, error) { file, err := os.Open(path) //nolint:gosec // paths are derived from the configured procfs root if err != nil { return nil, err } defer func() { _ = file.Close() }() data, err := io.ReadAll(io.LimitReader(file, limit)) if err != nil { return nil, err } return data, nil } func readTrimmed(path string, limit int64) (string, error) { data, err := readLimited(path, limit) if err != nil { return "", err } return strings.TrimSpace(string(data)), nil } // parseUint accepts the decimal unsigned values procfs uses and reports failure // instead of guessing, so a malformed line degrades one field rather than producing a // plausible-looking zero. func parseUint(value string) (uint64, bool) { parsed, err := strconv.ParseUint(strings.TrimSpace(value), 10, 64) if err != nil { return 0, false } return parsed, true } func parseFloat(value string) (float64, bool) { parsed, err := strconv.ParseFloat(strings.TrimSpace(value), 64) if err != nil { return 0, false } return parsed, true } func truncate(value string, max int) string { if len(value) > max { return value[:max] } return value } // lines splits procfs content without allocating a scanner per file. func lines(data []byte) []string { text := strings.TrimRight(string(data), "\n") if text == "" { return nil } return strings.Split(text, "\n") }