mirror of https://github.com/shirou/gopsutil
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
4.4 KiB
Go
191 lines
4.4 KiB
Go
// SPDX-License-Identifier: BSD-3-Clause
|
|
//go:build aix && !cgo
|
|
|
|
package disk
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/shirou/gopsutil/v4/internal/common"
|
|
)
|
|
|
|
var startBlank = regexp.MustCompile(`^\s+`)
|
|
|
|
var (
|
|
ignoreFSType = map[string]bool{"procfs": true}
|
|
FSType = map[int]string{
|
|
0: "jfs2", 1: "namefs", 2: "nfs", 3: "jfs", 5: "cdrom", 6: "proc",
|
|
16: "special-fs", 17: "cache-fs", 18: "nfs3", 19: "automount-fs", 20: "pool-fs", 32: "vxfs",
|
|
33: "veritas-fs", 34: "udfs", 35: "nfs4", 36: "nfs4-pseudo", 37: "smbfs", 38: "mcr-pseudofs",
|
|
39: "ahafs", 40: "sterm-nfs", 41: "asmfs",
|
|
}
|
|
)
|
|
|
|
func PartitionsWithContext(ctx context.Context, _ bool) ([]PartitionStat, error) {
|
|
var ret []PartitionStat
|
|
|
|
out, err := invoke.CommandWithContext(ctx, "mount")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// parse head lines for column names
|
|
colidx := make(map[string]int)
|
|
lines := strings.Split(string(out), "\n")
|
|
if len(lines) < 3 {
|
|
return nil, common.ErrNotImplementedError
|
|
}
|
|
|
|
idx := 0
|
|
start := 0
|
|
finished := false
|
|
for pos, ch := range lines[1] {
|
|
if ch == ' ' && !finished {
|
|
name := strings.TrimSpace(lines[0][start:pos])
|
|
colidx[name] = idx
|
|
finished = true
|
|
} else if ch == '-' && finished {
|
|
idx++
|
|
start = pos
|
|
finished = false
|
|
}
|
|
}
|
|
name := strings.TrimSpace(lines[0][start:len(lines[1])])
|
|
colidx[name] = idx
|
|
|
|
for idx := 2; idx < len(lines); idx++ {
|
|
line := lines[idx]
|
|
if startBlank.MatchString(line) {
|
|
line = "localhost" + line
|
|
}
|
|
p := strings.Fields(lines[idx])
|
|
if len(p) < 5 || ignoreFSType[p[colidx["vfs"]]] {
|
|
continue
|
|
}
|
|
d := PartitionStat{
|
|
Device: p[colidx["mounted"]],
|
|
Mountpoint: p[colidx["mounted over"]],
|
|
Fstype: p[colidx["vfs"]],
|
|
Opts: strings.Split(p[colidx["options"]], ","),
|
|
}
|
|
|
|
ret = append(ret, d)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func getFsType(stat unix.Statfs_t) string {
|
|
return FSType[int(stat.Vfstype)]
|
|
}
|
|
|
|
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
|
out, err := invoke.CommandWithContext(ctx, "df", "-v")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := &UsageStat{}
|
|
|
|
blocksize := uint64(512)
|
|
lines := strings.Split(string(out), "\n")
|
|
if len(lines) < 2 {
|
|
return &UsageStat{}, common.ErrNotImplementedError
|
|
}
|
|
|
|
hf := strings.Fields(strings.Replace(lines[0], "Mounted on", "Path", -1)) // headers
|
|
for line := 1; line < len(lines); line++ {
|
|
fs := strings.Fields(lines[line]) // values
|
|
for i, header := range hf {
|
|
// We're done in any of these use cases
|
|
if i >= len(fs) {
|
|
break
|
|
}
|
|
|
|
switch header {
|
|
case `Filesystem`:
|
|
// This is not a valid fs for us to parse
|
|
if fs[i] == "/proc" || fs[i] == "/ahafs" || fs[i] != path {
|
|
break
|
|
}
|
|
|
|
ret.Fstype, err = GetMountFSTypeWithContext(ctx, fs[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `Path`:
|
|
ret.Path = fs[i]
|
|
case `512-blocks`:
|
|
total, err := strconv.ParseUint(fs[i], 10, 64)
|
|
ret.Total = total * blocksize
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `Used`:
|
|
ret.Used, err = strconv.ParseUint(fs[i], 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `Free`:
|
|
ret.Free, err = strconv.ParseUint(fs[i], 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `%Used`:
|
|
val, err := strconv.ParseInt(strings.Replace(fs[i], "%", "", -1), 10, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.UsedPercent = float64(val) / float64(100)
|
|
case `Ifree`:
|
|
ret.InodesFree, err = strconv.ParseUint(fs[i], 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `Iused`:
|
|
ret.InodesUsed, err = strconv.ParseUint(fs[i], 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case `%Iused`:
|
|
val, err := strconv.ParseInt(strings.Replace(fs[i], "%", "", -1), 10, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.InodesUsedPercent = float64(val) / float64(100)
|
|
}
|
|
}
|
|
|
|
// Calculated value, since it isn't returned by the command
|
|
ret.InodesTotal = ret.InodesUsed + ret.InodesFree
|
|
|
|
// Valid Usage data, so append it
|
|
return ret, nil
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func GetMountFSTypeWithContext(ctx context.Context, mp string) (string, error) {
|
|
out, err := invoke.CommandWithContext(ctx, "mount")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Kind of inefficient, but it works
|
|
lines := strings.Split(string(out[:]), "\n")
|
|
for line := 1; line < len(lines); line++ {
|
|
fields := strings.Fields(lines[line])
|
|
if strings.TrimSpace(fields[0]) == mp {
|
|
return fields[2], nil
|
|
}
|
|
}
|
|
|
|
return "", nil
|
|
}
|