File: disk_aix_nocgo.go

package info (click to toggle)
golang-github-shirou-gopsutil 4.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 1,824 kB
  • sloc: makefile: 76; ansic: 19; sh: 11
file content (189 lines) | stat: -rw-r--r-- 4,554 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// SPDX-License-Identifier: BSD-3-Clause
//go:build aix && !cgo

package disk

import (
	"context"
	"regexp"
	"strconv"
	"strings"

	"github.com/shirou/gopsutil/v4/internal/common"
	"golang.org/x/sys/unix"
)

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, all 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
}