--- /dev/null 2026-04-17 05:15:00.245562212 -0500 +++ ./vendor/github.com/elastic/elastic-agent-system-metrics/metric/system/filesystem/filesystem_aix.go 2026-04-17 05:25:59.355648609 -0500 @@ -0,0 +1,139 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//go:build aix +// +build aix + +package filesystem + +import ( + "bufio" + "os" + "strings" + "fmt" + "golang.org/x/sys/unix" + "github.com/elastic/elastic-agent-libs/opt" + "github.com/elastic/elastic-agent-system-metrics/metric" +) + +func parseAIXFilesystems(path string) ([]FSStat, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + var entries []FSStat + scanner := bufio.NewScanner(file) + + var current FSStat + inStanza := false + + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" { + if inStanza && current.Device != "" { + entries = append(entries, current) + current = FSStat{} + inStanza = false + } + continue + } + + // New stanza begins + if !strings.Contains(line, "=") { + current.Directory = strings.TrimRight(line, ":") + inStanza = true + continue + } + + if !inStanza { + continue + } + + parts := strings.SplitN(line, "=", 2) + if len(parts) != 2 { + continue + } + key := strings.TrimSpace(parts[0]) + val := strings.TrimSpace(parts[1]) + + switch key { + case "dev": + current.Device = val + case "vfs": + current.Type = val + case "options": + current.Options = val + } + } + + // Append last stanza if necessary + if inStanza && current.Device != "" { + entries = append(entries, current) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return entries, nil +} + +// actually get the list of mounts on linux +func parseMounts(path string, filter func(FSStat) bool) ([]FSStat, error) { + //raw, err := os.ReadFile(path) + fsEntries, err := parseAIXFilesystems("/etc/filesystems") + if err != nil { + fmt.Fprintf(os.Stderr, "Error reading filesystems: %v\n", err) + return nil, err + } + + fsList := []FSStat{} + for _, fs := range fsEntries { + if fs.Device == "*" { + continue + } + + var stat unix.Statfs_t + unix.Statfs(fs.Device, &stat) + + total := stat.Blocks * uint64(stat.Bsize) + free := stat.Bfree * uint64(stat.Bsize) + avail := stat.Bavail * uint64(stat.Bsize) + + fs.Total = opt.UintWith(total) + fs.Free = opt.UintWith(free) + fs.Avail = opt.UintWith(avail) + + // Used = Total - Free + fs.Used.Bytes = fs.Total.SubtractOrNone(fs.Free) + + // Used pct = Used / (Used + Avail) + used := fs.Used.Bytes.ValueOr(0) + availVal := fs.Avail.ValueOr(0) + denominator := used + availVal + + if denominator != 0 { + percent := float64(used) / float64(denominator) + fs.Used.Pct = opt.FloatWith(metric.Round(percent)) + } + + fsList = append(fsList, fs) + } + return fsList, nil +}