summaryrefslogtreecommitdiff
path: root/vendor/github.com/shirou/gopsutil
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-05-11 21:12:57 -0600
committermo khan <mo@mokhan.ca>2025-05-11 21:12:57 -0600
commit60440f90dca28e99a31dd328c5f6d5dc0f9b6a2e (patch)
tree2f54adf55086516f162f0a55a5347e6b25f7f176 /vendor/github.com/shirou/gopsutil
parent05ca9b8d3a9c7203a3a3b590beaa400900bd9007 (diff)
chore: vendor go dependencies
Diffstat (limited to 'vendor/github.com/shirou/gopsutil')
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/LICENSE61
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/common/env.go25
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go202
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go16
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go66
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go157
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go198
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go80
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go13
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go157
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go31
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go170
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go479
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go120
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go10
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go137
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go50
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go270
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go227
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/binary.go638
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common.go474
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go402
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go82
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go356
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go66
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go66
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go42
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go304
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go11
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go22
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go31
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go40
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go51
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem.go121
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go22
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go51
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go78
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go87
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go130
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go34
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go167
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go506
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go87
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go100
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go38
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go33
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go38
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go38
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go38
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go68
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go213
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go182
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net.go356
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_aix.go299
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go36
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go95
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go271
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go71
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go108
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_linux.go807
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go343
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go168
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_unix.go188
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/net/net_windows.go729
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process.go640
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go76
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go480
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go258
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go234
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go203
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go363
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go218
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go224
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go218
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go226
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_linux.go1206
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go397
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go203
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go202
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go203
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go204
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go205
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go203
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_posix.go187
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go304
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_windows.go1180
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go108
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go79
100 files changed, 18502 insertions, 0 deletions
diff --git a/vendor/github.com/shirou/gopsutil/v4/LICENSE b/vendor/github.com/shirou/gopsutil/v4/LICENSE
new file mode 100644
index 0000000..6f06adc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/LICENSE
@@ -0,0 +1,61 @@
+gopsutil is distributed under BSD license reproduced below.
+
+Copyright (c) 2014, WAKAYAMA Shirou
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the gopsutil authors nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+-------
+internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go.
+
+
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/vendor/github.com/shirou/gopsutil/v4/common/env.go b/vendor/github.com/shirou/gopsutil/v4/common/env.go
new file mode 100644
index 0000000..47e471c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/common/env.go
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+type EnvKeyType string
+
+// EnvKey is a context key that can be used to set programmatically the environment
+// gopsutil relies on to perform calls against the OS.
+// Example of use:
+//
+// ctx := context.WithValue(context.Background(), common.EnvKey, EnvMap{common.HostProcEnvKey: "/myproc"})
+// avg, err := load.AvgWithContext(ctx)
+var EnvKey = EnvKeyType("env")
+
+const (
+ HostProcEnvKey EnvKeyType = "HOST_PROC"
+ HostSysEnvKey EnvKeyType = "HOST_SYS"
+ HostEtcEnvKey EnvKeyType = "HOST_ETC"
+ HostVarEnvKey EnvKeyType = "HOST_VAR"
+ HostRunEnvKey EnvKeyType = "HOST_RUN"
+ HostDevEnvKey EnvKeyType = "HOST_DEV"
+ HostRootEnvKey EnvKeyType = "HOST_ROOT"
+ HostProcMountinfo EnvKeyType = "HOST_PROC_MOUNTINFO"
+)
+
+type EnvMap map[EnvKeyType]string
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go
new file mode 100644
index 0000000..9bc3dfb
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// TimesStat contains the amounts of time the CPU has spent performing different
+// kinds of work. Time units are in seconds. It is based on linux /proc/stat file.
+type TimesStat struct {
+ CPU string `json:"cpu"`
+ User float64 `json:"user"`
+ System float64 `json:"system"`
+ Idle float64 `json:"idle"`
+ Nice float64 `json:"nice"`
+ Iowait float64 `json:"iowait"`
+ Irq float64 `json:"irq"`
+ Softirq float64 `json:"softirq"`
+ Steal float64 `json:"steal"`
+ Guest float64 `json:"guest"`
+ GuestNice float64 `json:"guestNice"`
+}
+
+type InfoStat struct {
+ CPU int32 `json:"cpu"`
+ VendorID string `json:"vendorId"`
+ Family string `json:"family"`
+ Model string `json:"model"`
+ Stepping int32 `json:"stepping"`
+ PhysicalID string `json:"physicalId"`
+ CoreID string `json:"coreId"`
+ Cores int32 `json:"cores"`
+ ModelName string `json:"modelName"`
+ Mhz float64 `json:"mhz"`
+ CacheSize int32 `json:"cacheSize"`
+ Flags []string `json:"flags"`
+ Microcode string `json:"microcode"`
+}
+
+type lastPercent struct {
+ sync.Mutex
+ lastCPUTimes []TimesStat
+ lastPerCPUTimes []TimesStat
+}
+
+var (
+ lastCPUPercent lastPercent
+ invoke common.Invoker = common.Invoke{}
+)
+
+func init() {
+ lastCPUPercent.Lock()
+ lastCPUPercent.lastCPUTimes, _ = Times(false)
+ lastCPUPercent.lastPerCPUTimes, _ = Times(true)
+ lastCPUPercent.Unlock()
+}
+
+// Counts returns the number of physical or logical cores in the system
+func Counts(logical bool) (int, error) {
+ return CountsWithContext(context.Background(), logical)
+}
+
+func (c TimesStat) String() string {
+ v := []string{
+ `"cpu":"` + c.CPU + `"`,
+ `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
+ `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
+ `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
+ `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
+ `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
+ `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
+ `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
+ `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
+ `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
+ `"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
+ }
+
+ return `{` + strings.Join(v, ",") + `}`
+}
+
+// Deprecated: Total returns the total number of seconds in a CPUTimesStat
+// Please do not use this internal function.
+func (c TimesStat) Total() float64 {
+ total := c.User + c.System + c.Idle + c.Nice + c.Iowait + c.Irq +
+ c.Softirq + c.Steal + c.Guest + c.GuestNice
+
+ return total
+}
+
+func (c InfoStat) String() string {
+ s, _ := json.Marshal(c)
+ return string(s)
+}
+
+func getAllBusy(t TimesStat) (float64, float64) {
+ tot := t.Total()
+ if runtime.GOOS == "linux" {
+ tot -= t.Guest // Linux 2.6.24+
+ tot -= t.GuestNice // Linux 3.2.0+
+ }
+
+ busy := tot - t.Idle - t.Iowait
+
+ return tot, busy
+}
+
+func calculateBusy(t1, t2 TimesStat) float64 {
+ t1All, t1Busy := getAllBusy(t1)
+ t2All, t2Busy := getAllBusy(t2)
+
+ if t2Busy <= t1Busy {
+ return 0
+ }
+ if t2All <= t1All {
+ return 100
+ }
+ return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))
+}
+
+func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
+ // Make sure the CPU measurements have the same length.
+ if len(t1) != len(t2) {
+ return nil, fmt.Errorf(
+ "received two CPU counts: %d != %d",
+ len(t1), len(t2),
+ )
+ }
+
+ ret := make([]float64, len(t1))
+ for i, t := range t2 {
+ ret[i] = calculateBusy(t1[i], t)
+ }
+ return ret, nil
+}
+
+// Percent calculates the percentage of cpu used either per CPU or combined.
+// If an interval of 0 is given it will compare the current cpu times against the last call.
+// Returns one value per cpu, or a single value if percpu is set to false.
+func Percent(interval time.Duration, percpu bool) ([]float64, error) {
+ return PercentWithContext(context.Background(), interval, percpu)
+}
+
+func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
+ if interval <= 0 {
+ return percentUsedFromLastCallWithContext(ctx, percpu)
+ }
+
+ // Get CPU usage at the start of the interval.
+ cpuTimes1, err := TimesWithContext(ctx, percpu)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := common.Sleep(ctx, interval); err != nil {
+ return nil, err
+ }
+
+ // And at the end of the interval.
+ cpuTimes2, err := TimesWithContext(ctx, percpu)
+ if err != nil {
+ return nil, err
+ }
+
+ return calculateAllBusy(cpuTimes1, cpuTimes2)
+}
+
+func percentUsedFromLastCall(percpu bool) ([]float64, error) {
+ return percentUsedFromLastCallWithContext(context.Background(), percpu)
+}
+
+func percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]float64, error) {
+ cpuTimes, err := TimesWithContext(ctx, percpu)
+ if err != nil {
+ return nil, err
+ }
+ lastCPUPercent.Lock()
+ defer lastCPUPercent.Unlock()
+ var lastTimes []TimesStat
+ if percpu {
+ lastTimes = lastCPUPercent.lastPerCPUTimes
+ lastCPUPercent.lastPerCPUTimes = cpuTimes
+ } else {
+ lastTimes = lastCPUPercent.lastCPUTimes
+ lastCPUPercent.lastCPUTimes = cpuTimes
+ }
+
+ if lastTimes == nil {
+ return nil, errors.New("error getting times for cpu percent. lastTimes was nil")
+ }
+ return calculateAllBusy(lastTimes, cpuTimes)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go
new file mode 100644
index 0000000..bc766bd
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package cpu
+
+import (
+ "context"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go
new file mode 100644
index 0000000..559dc5f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package cpu
+
+import (
+ "context"
+
+ "github.com/power-devops/perfstat"
+)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ var ret []TimesStat
+ if percpu {
+ cpus, err := perfstat.CpuStat()
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range cpus {
+ ct := &TimesStat{
+ CPU: c.Name,
+ Idle: float64(c.Idle),
+ User: float64(c.User),
+ System: float64(c.Sys),
+ Iowait: float64(c.Wait),
+ }
+ ret = append(ret, *ct)
+ }
+ } else {
+ c, err := perfstat.CpuUtilTotalStat()
+ if err != nil {
+ return nil, err
+ }
+ ct := &TimesStat{
+ CPU: "cpu-total",
+ Idle: float64(c.IdlePct),
+ User: float64(c.UserPct),
+ System: float64(c.KernPct),
+ Iowait: float64(c.WaitPct),
+ }
+ ret = append(ret, *ct)
+ }
+ return ret, nil
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ c, err := perfstat.CpuTotalStat()
+ if err != nil {
+ return nil, err
+ }
+ info := InfoStat{
+ CPU: 0,
+ Mhz: float64(c.ProcessorHz / 1000000),
+ Cores: int32(c.NCpusCfg),
+ }
+ result := []InfoStat{info}
+ return result, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ c, err := perfstat.CpuTotalStat()
+ if err != nil {
+ return 0, err
+ }
+ return c.NCpusCfg, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go
new file mode 100644
index 0000000..329ef83
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package cpu
+
+import (
+ "context"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ var ret []TimesStat
+ if percpu {
+ per_out, err := invoke.CommandWithContext(ctx, "sar", "-u", "-P", "ALL", "10", "1")
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(per_out), "\n")
+ if len(lines) < 6 {
+ return []TimesStat{}, common.ErrNotImplementedError
+ }
+
+ hp := strings.Fields(lines[5]) // headers
+ for l := 6; l < len(lines)-1; l++ {
+ ct := &TimesStat{}
+ v := strings.Fields(lines[l]) // values
+ for i, header := range hp {
+ // We're done in any of these use cases
+ if i >= len(v) || v[0] == "-" {
+ break
+ }
+
+ // Position variable for v
+ pos := i
+ // There is a missing field at the beginning of all but the first line
+ // so adjust the position
+ if l > 6 {
+ pos = i - 1
+ }
+ // We don't want invalid positions
+ if pos < 0 {
+ continue
+ }
+
+ if t, err := strconv.ParseFloat(v[pos], 64); err == nil {
+ switch header {
+ case `cpu`:
+ ct.CPU = strconv.FormatFloat(t, 'f', -1, 64)
+ case `%usr`:
+ ct.User = t
+ case `%sys`:
+ ct.System = t
+ case `%wio`:
+ ct.Iowait = t
+ case `%idle`:
+ ct.Idle = t
+ }
+ }
+ }
+ // Valid CPU data, so append it
+ ret = append(ret, *ct)
+ }
+ } else {
+ out, err := invoke.CommandWithContext(ctx, "sar", "-u", "10", "1")
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(out), "\n")
+ if len(lines) < 5 {
+ return []TimesStat{}, common.ErrNotImplementedError
+ }
+
+ ct := &TimesStat{CPU: "cpu-total"}
+ h := strings.Fields(lines[len(lines)-3]) // headers
+ v := strings.Fields(lines[len(lines)-2]) // values
+ for i, header := range h {
+ if t, err := strconv.ParseFloat(v[i], 64); err == nil {
+ switch header {
+ case `%usr`:
+ ct.User = t
+ case `%sys`:
+ ct.System = t
+ case `%wio`:
+ ct.Iowait = t
+ case `%idle`:
+ ct.Idle = t
+ }
+ }
+ }
+
+ ret = append(ret, *ct)
+ }
+
+ return ret, nil
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "prtconf")
+ if err != nil {
+ return nil, err
+ }
+
+ ret := InfoStat{}
+ for _, line := range strings.Split(string(out), "\n") {
+ if strings.HasPrefix(line, "Number Of Processors:") {
+ p := strings.Fields(line)
+ if len(p) > 3 {
+ if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+ ret.Cores = int32(t)
+ }
+ }
+ } else if strings.HasPrefix(line, "Processor Clock Speed:") {
+ p := strings.Fields(line)
+ if len(p) > 4 {
+ if t, err := strconv.ParseFloat(p[3], 64); err == nil {
+ switch strings.ToUpper(p[4]) {
+ case "MHZ":
+ ret.Mhz = t
+ case "GHZ":
+ ret.Mhz = t * 1000.0
+ case "KHZ":
+ ret.Mhz = t / 1000.0
+ default:
+ ret.Mhz = t
+ }
+ }
+ }
+ break
+ } else if strings.HasPrefix(line, "System Model:") {
+ p := strings.Split(string(line), ":")
+ if p != nil {
+ ret.VendorID = strings.TrimSpace(p[1])
+ }
+ } else if strings.HasPrefix(line, "Processor Type:") {
+ p := strings.Split(string(line), ":")
+ if p != nil {
+ c := strings.Split(string(p[1]), "_")
+ if c != nil {
+ ret.Family = strings.TrimSpace(c[0])
+ ret.Model = strings.TrimSpace(c[1])
+ }
+ }
+ }
+ }
+ return []InfoStat{ret}, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ info, err := InfoWithContext(ctx)
+ if err == nil {
+ return int(info[0].Cores), nil
+ }
+ return 0, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go
new file mode 100644
index 0000000..b3e3a66
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// sys/resource.h
+const (
+ CPUser = 0
+ cpNice = 1
+ cpSys = 2
+ cpIntr = 3
+ cpIdle = 4
+ cpUStates = 5
+)
+
+// mach/machine.h
+const (
+ cpuStateUser = 0
+ cpuStateSystem = 1
+ cpuStateIdle = 2
+ cpuStateNice = 3
+ cpuStateMax = 4
+)
+
+// mach/processor_info.h
+const (
+ processorCpuLoadInfo = 2
+)
+
+type hostCpuLoadInfoData struct {
+ cpuTicks [cpuStateMax]uint32
+}
+
+// default value. from time.h
+var ClocksPerSec = float64(128)
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ lib, err := common.NewLibrary(common.System)
+ if err != nil {
+ return nil, err
+ }
+ defer lib.Close()
+
+ if percpu {
+ return perCPUTimes(lib)
+ }
+
+ return allCPUTimes(lib)
+}
+
+// Returns only one CPUInfoStat on FreeBSD
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+
+ c := InfoStat{}
+ c.ModelName, _ = unix.Sysctl("machdep.cpu.brand_string")
+ family, _ := unix.SysctlUint32("machdep.cpu.family")
+ c.Family = strconv.FormatUint(uint64(family), 10)
+ model, _ := unix.SysctlUint32("machdep.cpu.model")
+ c.Model = strconv.FormatUint(uint64(model), 10)
+ stepping, _ := unix.SysctlUint32("machdep.cpu.stepping")
+ c.Stepping = int32(stepping)
+ features, err := unix.Sysctl("machdep.cpu.features")
+ if err == nil {
+ for _, v := range strings.Fields(features) {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ }
+ leaf7Features, err := unix.Sysctl("machdep.cpu.leaf7_features")
+ if err == nil {
+ for _, v := range strings.Fields(leaf7Features) {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ }
+ extfeatures, err := unix.Sysctl("machdep.cpu.extfeatures")
+ if err == nil {
+ for _, v := range strings.Fields(extfeatures) {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ }
+ cores, _ := unix.SysctlUint32("machdep.cpu.core_count")
+ c.Cores = int32(cores)
+ cacheSize, _ := unix.SysctlUint32("machdep.cpu.cache.size")
+ c.CacheSize = int32(cacheSize)
+ c.VendorID, _ = unix.Sysctl("machdep.cpu.vendor")
+
+ v, err := getFrequency()
+ if err == nil {
+ c.Mhz = v
+ }
+
+ return append(ret, c), nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ var cpuArgument string
+ if logical {
+ cpuArgument = "hw.logicalcpu"
+ } else {
+ cpuArgument = "hw.physicalcpu"
+ }
+
+ count, err := unix.SysctlUint32(cpuArgument)
+ if err != nil {
+ return 0, err
+ }
+
+ return int(count), nil
+}
+
+func perCPUTimes(machLib *common.Library) ([]TimesStat, error) {
+ machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym)
+ machTaskSelf := common.GetFunc[common.MachTaskSelfFunc](machLib, common.MachTaskSelfSym)
+ hostProcessorInfo := common.GetFunc[common.HostProcessorInfoFunc](machLib, common.HostProcessorInfoSym)
+ vmDeallocate := common.GetFunc[common.VMDeallocateFunc](machLib, common.VMDeallocateSym)
+
+ var count, ncpu uint32
+ var cpuload *hostCpuLoadInfoData
+
+ status := hostProcessorInfo(machHostSelf(), processorCpuLoadInfo, &ncpu, uintptr(unsafe.Pointer(&cpuload)), &count)
+
+ if status != common.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_processor_info error=%d", status)
+ }
+
+ defer vmDeallocate(machTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu))
+
+ ret := []TimesStat{}
+ loads := unsafe.Slice(cpuload, ncpu)
+
+ for i := 0; i < int(ncpu); i++ {
+ c := TimesStat{
+ CPU: fmt.Sprintf("cpu%d", i),
+ User: float64(loads[i].cpuTicks[cpuStateUser]) / ClocksPerSec,
+ System: float64(loads[i].cpuTicks[cpuStateSystem]) / ClocksPerSec,
+ Nice: float64(loads[i].cpuTicks[cpuStateNice]) / ClocksPerSec,
+ Idle: float64(loads[i].cpuTicks[cpuStateIdle]) / ClocksPerSec,
+ }
+
+ ret = append(ret, c)
+ }
+
+ return ret, nil
+}
+
+func allCPUTimes(machLib *common.Library) ([]TimesStat, error) {
+ machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym)
+ hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym)
+
+ var cpuload hostCpuLoadInfoData
+ count := uint32(cpuStateMax)
+
+ status := hostStatistics(machHostSelf(), common.HOST_CPU_LOAD_INFO,
+ uintptr(unsafe.Pointer(&cpuload)), &count)
+
+ if status != common.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_statistics error=%d", status)
+ }
+
+ c := TimesStat{
+ CPU: "cpu-total",
+ User: float64(cpuload.cpuTicks[cpuStateUser]) / ClocksPerSec,
+ System: float64(cpuload.cpuTicks[cpuStateSystem]) / ClocksPerSec,
+ Nice: float64(cpuload.cpuTicks[cpuStateNice]) / ClocksPerSec,
+ Idle: float64(cpuload.cpuTicks[cpuStateIdle]) / ClocksPerSec,
+ }
+
+ return []TimesStat{c}, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go
new file mode 100644
index 0000000..0942700
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && arm64
+
+package cpu
+
+import (
+ "encoding/binary"
+ "fmt"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go
+func getFrequency() (float64, error) {
+ ioKit, err := common.NewLibrary(common.IOKit)
+ if err != nil {
+ return 0, err
+ }
+ defer ioKit.Close()
+
+ coreFoundation, err := common.NewLibrary(common.CoreFoundation)
+ if err != nil {
+ return 0, err
+ }
+ defer coreFoundation.Close()
+
+ ioServiceMatching := common.GetFunc[common.IOServiceMatchingFunc](ioKit, common.IOServiceMatchingSym)
+ ioServiceGetMatchingServices := common.GetFunc[common.IOServiceGetMatchingServicesFunc](ioKit, common.IOServiceGetMatchingServicesSym)
+ ioIteratorNext := common.GetFunc[common.IOIteratorNextFunc](ioKit, common.IOIteratorNextSym)
+ ioRegistryEntryGetName := common.GetFunc[common.IORegistryEntryGetNameFunc](ioKit, common.IORegistryEntryGetNameSym)
+ ioRegistryEntryCreateCFProperty := common.GetFunc[common.IORegistryEntryCreateCFPropertyFunc](ioKit, common.IORegistryEntryCreateCFPropertySym)
+ ioObjectRelease := common.GetFunc[common.IOObjectReleaseFunc](ioKit, common.IOObjectReleaseSym)
+
+ cfStringCreateWithCString := common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym)
+ cfDataGetLength := common.GetFunc[common.CFDataGetLengthFunc](coreFoundation, common.CFDataGetLengthSym)
+ cfDataGetBytePtr := common.GetFunc[common.CFDataGetBytePtrFunc](coreFoundation, common.CFDataGetBytePtrSym)
+ cfRelease := common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym)
+
+ matching := ioServiceMatching("AppleARMIODevice")
+
+ var iterator uint32
+ if status := ioServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS {
+ return 0.0, fmt.Errorf("IOServiceGetMatchingServices error=%d", status)
+ }
+ defer ioObjectRelease(iterator)
+
+ pCorekey := cfStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8)
+ defer cfRelease(uintptr(pCorekey))
+
+ var pCoreHz uint32
+ for {
+ service := ioIteratorNext(iterator)
+ if !(service > 0) {
+ break
+ }
+
+ buf := common.NewCStr(512)
+ ioRegistryEntryGetName(service, buf)
+
+ if buf.GoString() == "pmgr" {
+ pCoreRef := ioRegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions)
+ length := cfDataGetLength(uintptr(pCoreRef))
+ data := cfDataGetBytePtr(uintptr(pCoreRef))
+
+ // composite uint32 from the byte array
+ buf := unsafe.Slice((*byte)(data), length)
+
+ // combine the bytes into a uint32 value
+ b := buf[length-8 : length-4]
+ pCoreHz = binary.LittleEndian.Uint32(b)
+ ioObjectRelease(service)
+ break
+ }
+
+ ioObjectRelease(service)
+ }
+
+ return float64(pCoreHz / 1_000_000), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go
new file mode 100644
index 0000000..b9e52ab
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && !arm64
+
+package cpu
+
+import "golang.org/x/sys/unix"
+
+func getFrequency() (float64, error) {
+ // Use the rated frequency of the CPU. This is a static value and does not
+ // account for low power or Turbo Boost modes.
+ cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency")
+ return float64(cpuFrequency) / 1000000.0, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go
new file mode 100644
index 0000000..19b1e9d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+)
+
+var (
+ ClocksPerSec = float64(128)
+ cpuMatch = regexp.MustCompile(`^CPU:`)
+ originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`)
+ featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`)
+ featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
+ cpuEnd = regexp.MustCompile(`^Trying to mount root`)
+ cpuTimesSize int
+ emptyTimes cpuTimes
+)
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func timeStat(name string, t *cpuTimes) *TimesStat {
+ return &TimesStat{
+ User: float64(t.User) / ClocksPerSec,
+ Nice: float64(t.Nice) / ClocksPerSec,
+ System: float64(t.Sys) / ClocksPerSec,
+ Idle: float64(t.Idle) / ClocksPerSec,
+ Irq: float64(t.Intr) / ClocksPerSec,
+ CPU: name,
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ buf, err := unix.SysctlRaw("kern.cp_times")
+ if err != nil {
+ return nil, err
+ }
+
+ // We can't do this in init due to the conflict with cpu.init()
+ if cpuTimesSize == 0 {
+ cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
+ }
+
+ ncpus := len(buf) / cpuTimesSize
+ ret := make([]TimesStat, 0, ncpus)
+ for i := 0; i < ncpus; i++ {
+ times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
+ if *times == emptyTimes {
+ // CPU not present
+ continue
+ }
+ ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
+ }
+ return ret, nil
+ }
+
+ buf, err := unix.SysctlRaw("kern.cp_time")
+ if err != nil {
+ return nil, err
+ }
+
+ times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ return []TimesStat{*timeStat("cpu-total", times)}, nil
+}
+
+// Returns only one InfoStat on DragonflyBSD. The information regarding core
+// count, however is accurate and it is assumed that all InfoStat attributes
+// are the same across CPUs.
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ const dmesgBoot = "/var/run/dmesg.boot"
+
+ c, err := parseDmesgBoot(dmesgBoot)
+ if err != nil {
+ return nil, err
+ }
+
+ var u32 uint32
+ if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
+ return nil, err
+ }
+ c.Mhz = float64(u32)
+
+ var num int
+ var buf string
+ if buf, err = unix.Sysctl("hw.cpu_topology.tree"); err != nil {
+ return nil, err
+ }
+ num = strings.Count(buf, "CHIP")
+ c.Cores = int32(strings.Count(string(buf), "CORE") / num)
+
+ if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+ return nil, err
+ }
+
+ ret := make([]InfoStat, num)
+ for i := 0; i < num; i++ {
+ ret[i] = c
+ }
+
+ return ret, nil
+}
+
+func parseDmesgBoot(fileName string) (InfoStat, error) {
+ c := InfoStat{}
+ lines, _ := common.ReadLines(fileName)
+ for _, line := range lines {
+ if matches := cpuEnd.FindStringSubmatch(line); matches != nil {
+ break
+ } else if matches := originMatch.FindStringSubmatch(line); matches != nil {
+ c.VendorID = matches[1]
+ t, err := strconv.ParseInt(matches[2], 10, 32)
+ if err != nil {
+ return c, fmt.Errorf("unable to parse DragonflyBSD CPU stepping information from %q: %v", line, err)
+ }
+ c.Stepping = int32(t)
+ } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ }
+ }
+
+ return c, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go
new file mode 100644
index 0000000..25ececa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go
new file mode 100644
index 0000000..245c1ec
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix
+
+package cpu
+
+import (
+ "context"
+ "runtime"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ return []TimesStat{}, common.ErrNotImplementedError
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ return []InfoStat{}, common.ErrNotImplementedError
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go
new file mode 100644
index 0000000..5d17c7e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+ ClocksPerSec = float64(128)
+ cpuMatch = regexp.MustCompile(`^CPU:`)
+ originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`)
+ featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`)
+ featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
+ cpuEnd = regexp.MustCompile(`^Trying to mount root`)
+ cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`)
+ cpuTimesSize int
+ emptyTimes cpuTimes
+)
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func timeStat(name string, t *cpuTimes) *TimesStat {
+ return &TimesStat{
+ User: float64(t.User) / ClocksPerSec,
+ Nice: float64(t.Nice) / ClocksPerSec,
+ System: float64(t.Sys) / ClocksPerSec,
+ Idle: float64(t.Idle) / ClocksPerSec,
+ Irq: float64(t.Intr) / ClocksPerSec,
+ CPU: name,
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ buf, err := unix.SysctlRaw("kern.cp_times")
+ if err != nil {
+ return nil, err
+ }
+
+ // We can't do this in init due to the conflict with cpu.init()
+ if cpuTimesSize == 0 {
+ cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
+ }
+
+ ncpus := len(buf) / cpuTimesSize
+ ret := make([]TimesStat, 0, ncpus)
+ for i := 0; i < ncpus; i++ {
+ times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
+ if *times == emptyTimes {
+ // CPU not present
+ continue
+ }
+ ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
+ }
+ return ret, nil
+ }
+
+ buf, err := unix.SysctlRaw("kern.cp_time")
+ if err != nil {
+ return nil, err
+ }
+
+ times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ return []TimesStat{*timeStat("cpu-total", times)}, nil
+}
+
+// Returns only one InfoStat on FreeBSD. The information regarding core
+// count, however is accurate and it is assumed that all InfoStat attributes
+// are the same across CPUs.
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ const dmesgBoot = "/var/run/dmesg.boot"
+
+ c, num, err := parseDmesgBoot(dmesgBoot)
+ if err != nil {
+ return nil, err
+ }
+
+ var u32 uint32
+ if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
+ return nil, err
+ }
+ c.Mhz = float64(u32)
+
+ if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil {
+ return nil, err
+ }
+ c.Cores = int32(u32)
+
+ if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+ return nil, err
+ }
+
+ ret := make([]InfoStat, num)
+ for i := 0; i < num; i++ {
+ ret[i] = c
+ }
+
+ return ret, nil
+}
+
+func parseDmesgBoot(fileName string) (InfoStat, int, error) {
+ c := InfoStat{}
+ lines, _ := common.ReadLines(fileName)
+ cpuNum := 1 // default cpu num is 1
+ for _, line := range lines {
+ if matches := cpuEnd.FindStringSubmatch(line); matches != nil {
+ break
+ } else if matches := originMatch.FindStringSubmatch(line); matches != nil {
+ c.VendorID = matches[1]
+ c.Family = matches[3]
+ c.Model = matches[4]
+ t, err := strconv.ParseInt(matches[5], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU stepping information from %q: %w", line, err)
+ }
+ c.Stepping = int32(t)
+ } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if matches := cpuCores.FindStringSubmatch(line); matches != nil {
+ t, err := strconv.ParseInt(matches[1], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU Nums from %q: %w", line, err)
+ }
+ cpuNum = int(t)
+ t2, err := strconv.ParseInt(matches[2], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU cores from %q: %w", line, err)
+ }
+ c.Cores = int32(t2)
+ }
+ }
+
+ return c, cpuNum, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go
new file mode 100644
index 0000000..e4799bc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go
new file mode 100644
index 0000000..25ececa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go
new file mode 100644
index 0000000..e4799bc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go
new file mode 100644
index 0000000..25ececa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go
new file mode 100644
index 0000000..5f595e7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package cpu
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/tklauser/go-sysconf"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var ClocksPerSec = float64(100)
+
+var armModelToModelName = map[uint64]string{
+ 0x810: "ARM810",
+ 0x920: "ARM920",
+ 0x922: "ARM922",
+ 0x926: "ARM926",
+ 0x940: "ARM940",
+ 0x946: "ARM946",
+ 0x966: "ARM966",
+ 0xa20: "ARM1020",
+ 0xa22: "ARM1022",
+ 0xa26: "ARM1026",
+ 0xb02: "ARM11 MPCore",
+ 0xb36: "ARM1136",
+ 0xb56: "ARM1156",
+ 0xb76: "ARM1176",
+ 0xc05: "Cortex-A5",
+ 0xc07: "Cortex-A7",
+ 0xc08: "Cortex-A8",
+ 0xc09: "Cortex-A9",
+ 0xc0d: "Cortex-A17",
+ 0xc0f: "Cortex-A15",
+ 0xc0e: "Cortex-A17",
+ 0xc14: "Cortex-R4",
+ 0xc15: "Cortex-R5",
+ 0xc17: "Cortex-R7",
+ 0xc18: "Cortex-R8",
+ 0xc20: "Cortex-M0",
+ 0xc21: "Cortex-M1",
+ 0xc23: "Cortex-M3",
+ 0xc24: "Cortex-M4",
+ 0xc27: "Cortex-M7",
+ 0xc60: "Cortex-M0+",
+ 0xd01: "Cortex-A32",
+ 0xd02: "Cortex-A34",
+ 0xd03: "Cortex-A53",
+ 0xd04: "Cortex-A35",
+ 0xd05: "Cortex-A55",
+ 0xd06: "Cortex-A65",
+ 0xd07: "Cortex-A57",
+ 0xd08: "Cortex-A72",
+ 0xd09: "Cortex-A73",
+ 0xd0a: "Cortex-A75",
+ 0xd0b: "Cortex-A76",
+ 0xd0c: "Neoverse-N1",
+ 0xd0d: "Cortex-A77",
+ 0xd0e: "Cortex-A76AE",
+ 0xd13: "Cortex-R52",
+ 0xd20: "Cortex-M23",
+ 0xd21: "Cortex-M33",
+ 0xd40: "Neoverse-V1",
+ 0xd41: "Cortex-A78",
+ 0xd42: "Cortex-A78AE",
+ 0xd43: "Cortex-A65AE",
+ 0xd44: "Cortex-X1",
+ 0xd46: "Cortex-A510",
+ 0xd47: "Cortex-A710",
+ 0xd48: "Cortex-X2",
+ 0xd49: "Neoverse-N2",
+ 0xd4a: "Neoverse-E1",
+ 0xd4b: "Cortex-A78C",
+ 0xd4c: "Cortex-X1C",
+ 0xd4d: "Cortex-A715",
+ 0xd4e: "Cortex-X3",
+}
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ filename := common.HostProcWithContext(ctx, "stat")
+ lines := []string{}
+ if percpu {
+ statlines, err := common.ReadLines(filename)
+ if err != nil || len(statlines) < 2 {
+ return []TimesStat{}, nil
+ }
+ for _, line := range statlines[1:] {
+ if !strings.HasPrefix(line, "cpu") {
+ break
+ }
+ lines = append(lines, line)
+ }
+ } else {
+ lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
+ }
+
+ ret := make([]TimesStat, 0, len(lines))
+
+ for _, line := range lines {
+ ct, err := parseStatLine(line)
+ if err != nil {
+ continue
+ }
+ ret = append(ret, *ct)
+
+ }
+ return ret, nil
+}
+
+func sysCPUPath(ctx context.Context, cpu int32, relPath string) string {
+ return common.HostSysWithContext(ctx, fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
+}
+
+func finishCPUInfo(ctx context.Context, c *InfoStat) {
+ var lines []string
+ var err error
+ var value float64
+
+ if len(c.CoreID) == 0 {
+ lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "topology/core_id"))
+ if err == nil {
+ c.CoreID = lines[0]
+ }
+ }
+
+ // override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
+ // of the value from /proc/cpuinfo because we want to report the maximum
+ // clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
+ lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "cpufreq/cpuinfo_max_freq"))
+ // if we encounter errors below such as there are no cpuinfo_max_freq file,
+ // we just ignore. so let Mhz is 0.
+ if err != nil || len(lines) == 0 {
+ return
+ }
+ value, err = strconv.ParseFloat(lines[0], 64)
+ if err != nil {
+ return
+ }
+ c.Mhz = value / 1000.0 // value is in kHz
+ if c.Mhz > 9999 {
+ c.Mhz = c.Mhz / 1000.0 // value in Hz
+ }
+}
+
+// CPUInfo on linux will return 1 item per physical thread.
+//
+// CPUs have three levels of counting: sockets, cores, threads.
+// Cores with HyperThreading count as having 2 threads per core.
+// Sockets often come with many physical CPU cores.
+// For example a single socket board with two cores each with HT will
+// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ filename := common.HostProcWithContext(ctx, "cpuinfo")
+ lines, _ := common.ReadLines(filename)
+
+ var ret []InfoStat
+ var processorName string
+
+ c := InfoStat{CPU: -1, Cores: 1}
+ for _, line := range lines {
+ fields := strings.Split(line, ":")
+ if len(fields) < 2 {
+ continue
+ }
+ key := strings.TrimSpace(fields[0])
+ value := strings.TrimSpace(fields[1])
+
+ switch key {
+ case "Processor":
+ processorName = value
+ case "processor", "cpu number":
+ if c.CPU >= 0 {
+ finishCPUInfo(ctx, &c)
+ ret = append(ret, c)
+ }
+ c = InfoStat{Cores: 1, ModelName: processorName}
+ t, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.CPU = int32(t)
+ case "vendorId", "vendor_id":
+ c.VendorID = value
+ if strings.Contains(value, "S390") {
+ processorName = "S390"
+ }
+ case "CPU implementer":
+ if v, err := strconv.ParseUint(value, 0, 8); err == nil {
+ switch v {
+ case 0x41:
+ c.VendorID = "ARM"
+ case 0x42:
+ c.VendorID = "Broadcom"
+ case 0x43:
+ c.VendorID = "Cavium"
+ case 0x44:
+ c.VendorID = "DEC"
+ case 0x46:
+ c.VendorID = "Fujitsu"
+ case 0x48:
+ c.VendorID = "HiSilicon"
+ case 0x49:
+ c.VendorID = "Infineon"
+ case 0x4d:
+ c.VendorID = "Motorola/Freescale"
+ case 0x4e:
+ c.VendorID = "NVIDIA"
+ case 0x50:
+ c.VendorID = "APM"
+ case 0x51:
+ c.VendorID = "Qualcomm"
+ case 0x56:
+ c.VendorID = "Marvell"
+ case 0x61:
+ c.VendorID = "Apple"
+ case 0x69:
+ c.VendorID = "Intel"
+ case 0xc0:
+ c.VendorID = "Ampere"
+ }
+ }
+ case "cpu family":
+ c.Family = value
+ case "model", "CPU part":
+ c.Model = value
+ // if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c
+ if c.VendorID == "ARM" {
+ if v, err := strconv.ParseUint(c.Model, 0, 16); err == nil {
+ modelName, exist := armModelToModelName[v]
+ if exist {
+ c.ModelName = modelName
+ } else {
+ c.ModelName = "Undefined"
+ }
+ }
+ }
+ case "Model Name", "model name", "cpu":
+ c.ModelName = value
+ if strings.Contains(value, "POWER") {
+ c.Model = strings.Split(value, " ")[0]
+ c.Family = "POWER"
+ c.VendorID = "IBM"
+ }
+ case "stepping", "revision", "CPU revision":
+ val := value
+
+ if key == "revision" {
+ val = strings.Split(value, ".")[0]
+ }
+
+ t, err := strconv.ParseInt(val, 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.Stepping = int32(t)
+ case "cpu MHz", "clock", "cpu MHz dynamic":
+ // treat this as the fallback value, thus we ignore error
+ if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil {
+ c.Mhz = t
+ }
+ case "cache size":
+ t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.CacheSize = int32(t)
+ case "physical id":
+ c.PhysicalID = value
+ case "core id":
+ c.CoreID = value
+ case "flags", "Features":
+ c.Flags = strings.FieldsFunc(value, func(r rune) bool {
+ return r == ',' || r == ' '
+ })
+ case "microcode":
+ c.Microcode = value
+ }
+ }
+ if c.CPU >= 0 {
+ finishCPUInfo(ctx, &c)
+ ret = append(ret, c)
+ }
+ return ret, nil
+}
+
+func parseStatLine(line string) (*TimesStat, error) {
+ fields := strings.Fields(line)
+
+ if len(fields) < 8 {
+ return nil, errors.New("stat does not contain cpu info")
+ }
+
+ if !strings.HasPrefix(fields[0], "cpu") {
+ return nil, errors.New("not contain cpu")
+ }
+
+ cpu := fields[0]
+ if cpu == "cpu" {
+ cpu = "cpu-total"
+ }
+ user, err := strconv.ParseFloat(fields[1], 64)
+ if err != nil {
+ return nil, err
+ }
+ nice, err := strconv.ParseFloat(fields[2], 64)
+ if err != nil {
+ return nil, err
+ }
+ system, err := strconv.ParseFloat(fields[3], 64)
+ if err != nil {
+ return nil, err
+ }
+ idle, err := strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, err
+ }
+ iowait, err := strconv.ParseFloat(fields[5], 64)
+ if err != nil {
+ return nil, err
+ }
+ irq, err := strconv.ParseFloat(fields[6], 64)
+ if err != nil {
+ return nil, err
+ }
+ softirq, err := strconv.ParseFloat(fields[7], 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ct := &TimesStat{
+ CPU: cpu,
+ User: user / ClocksPerSec,
+ Nice: nice / ClocksPerSec,
+ System: system / ClocksPerSec,
+ Idle: idle / ClocksPerSec,
+ Iowait: iowait / ClocksPerSec,
+ Irq: irq / ClocksPerSec,
+ Softirq: softirq / ClocksPerSec,
+ }
+ if len(fields) > 8 { // Linux >= 2.6.11
+ steal, err := strconv.ParseFloat(fields[8], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.Steal = steal / ClocksPerSec
+ }
+ if len(fields) > 9 { // Linux >= 2.6.24
+ guest, err := strconv.ParseFloat(fields[9], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.Guest = guest / ClocksPerSec
+ }
+ if len(fields) > 10 { // Linux >= 3.2.0
+ guestNice, err := strconv.ParseFloat(fields[10], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.GuestNice = guestNice / ClocksPerSec
+ }
+
+ return ct, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ if logical {
+ ret := 0
+ // https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599
+ procCpuinfo := common.HostProcWithContext(ctx, "cpuinfo")
+ lines, err := common.ReadLines(procCpuinfo)
+ if err == nil {
+ for _, line := range lines {
+ line = strings.ToLower(line)
+ if strings.HasPrefix(line, "processor") {
+ _, err = strconv.ParseInt(strings.TrimSpace(line[strings.IndexByte(line, ':')+1:]), 10, 32)
+ if err == nil {
+ ret++
+ }
+ }
+ }
+ }
+ if ret == 0 {
+ procStat := common.HostProcWithContext(ctx, "stat")
+ lines, err = common.ReadLines(procStat)
+ if err != nil {
+ return 0, err
+ }
+ for _, line := range lines {
+ if len(line) >= 4 && strings.HasPrefix(line, "cpu") && '0' <= line[3] && line[3] <= '9' { // `^cpu\d` regexp matching
+ ret++
+ }
+ }
+ }
+ return ret, nil
+ }
+ // physical cores
+ // https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/_pslinux.py#L615-L628
+ threadSiblingsLists := make(map[string]bool)
+ // These 2 files are the same but */core_cpus_list is newer while */thread_siblings_list is deprecated and may disappear in the future.
+ // https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
+ // https://github.com/giampaolo/psutil/pull/1727#issuecomment-707624964
+ // https://lkml.org/lkml/2019/2/26/41
+ for _, glob := range []string{"devices/system/cpu/cpu[0-9]*/topology/core_cpus_list", "devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list"} {
+ if files, err := filepath.Glob(common.HostSysWithContext(ctx, glob)); err == nil {
+ for _, file := range files {
+ lines, err := common.ReadLines(file)
+ if err != nil || len(lines) != 1 {
+ continue
+ }
+ threadSiblingsLists[lines[0]] = true
+ }
+ ret := len(threadSiblingsLists)
+ if ret != 0 {
+ return ret, nil
+ }
+ }
+ }
+ // https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652
+ filename := common.HostProcWithContext(ctx, "cpuinfo")
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return 0, err
+ }
+ mapping := make(map[int]int)
+ currentInfo := make(map[string]int)
+ for _, line := range lines {
+ line = strings.ToLower(strings.TrimSpace(line))
+ if line == "" {
+ // new section
+ id, okID := currentInfo["physical id"]
+ cores, okCores := currentInfo["cpu cores"]
+ if okID && okCores {
+ mapping[id] = cores
+ }
+ currentInfo = make(map[string]int)
+ continue
+ }
+ fields := strings.Split(line, ":")
+ if len(fields) < 2 {
+ continue
+ }
+ fields[0] = strings.TrimSpace(fields[0])
+ if fields[0] == "physical id" || fields[0] == "cpu cores" {
+ val, err := strconv.ParseInt(strings.TrimSpace(fields[1]), 10, 32)
+ if err != nil {
+ continue
+ }
+ currentInfo[fields[0]] = int(val)
+ }
+ }
+ ret := 0
+ for _, v := range mapping {
+ ret += v
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go
new file mode 100644
index 0000000..198be5e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "runtime"
+ "unsafe"
+
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+const (
+ // sys/sysctl.h
+ ctlKern = 1 // "high kernel": proc, limits
+ ctlHw = 6 // CTL_HW
+ kernCpTime = 51 // KERN_CPTIME
+)
+
+var ClocksPerSec = float64(100)
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) {
+ if !percpu {
+ mib := []int32{ctlKern, kernCpTime}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return ret, err
+ }
+ times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ stat := TimesStat{
+ CPU: "cpu-total",
+ User: float64(times.User),
+ Nice: float64(times.Nice),
+ System: float64(times.Sys),
+ Idle: float64(times.Idle),
+ Irq: float64(times.Intr),
+ }
+ return []TimesStat{stat}, nil
+ }
+
+ ncpu, err := unix.SysctlUint32("hw.ncpu")
+ if err != nil {
+ return
+ }
+
+ var i uint32
+ for i = 0; i < ncpu; i++ {
+ mib := []int32{ctlKern, kernCpTime, int32(i)}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return ret, err
+ }
+
+ stats := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ ret = append(ret, TimesStat{
+ CPU: fmt.Sprintf("cpu%d", i),
+ User: float64(stats.User),
+ Nice: float64(stats.Nice),
+ System: float64(stats.Sys),
+ Idle: float64(stats.Idle),
+ Irq: float64(stats.Intr),
+ })
+ }
+
+ return ret, nil
+}
+
+// Returns only one (minimal) CPUInfoStat on NetBSD
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+ var err error
+
+ c := InfoStat{}
+
+ mhz, err := unix.Sysctl("machdep.dmi.processor-frequency")
+ if err != nil {
+ return nil, err
+ }
+ _, err = fmt.Sscanf(mhz, "%f", &c.Mhz)
+ if err != nil {
+ return nil, err
+ }
+
+ ncpu, err := unix.SysctlUint32("hw.ncpuonline")
+ if err != nil {
+ return nil, err
+ }
+ c.Cores = int32(ncpu)
+
+ if c.ModelName, err = unix.Sysctl("machdep.dmi.processor-version"); err != nil {
+ return nil, err
+ }
+
+ return append(ret, c), nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go
new file mode 100644
index 0000000..25ececa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go
new file mode 100644
index 0000000..e4799bc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go
new file mode 100644
index 0000000..25ececa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go
new file mode 100644
index 0000000..33233d3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "runtime"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+)
+
+const (
+ // sys/sched.h
+ cpuOnline = 0x0001 // CPUSTATS_ONLINE
+
+ // sys/sysctl.h
+ ctlKern = 1 // "high kernel": proc, limits
+ ctlHw = 6 // CTL_HW
+ smt = 24 // HW_SMT
+ kernCpTime = 40 // KERN_CPTIME
+ kernCPUStats = 85 // KERN_CPUSTATS
+)
+
+var ClocksPerSec = float64(128)
+
+type cpuStats struct {
+ // cs_time[CPUSTATES]
+ User uint64
+ Nice uint64
+ Sys uint64
+ Spin uint64
+ Intr uint64
+ Idle uint64
+
+ // cs_flags
+ Flags uint64
+}
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) {
+ if !percpu {
+ mib := []int32{ctlKern, kernCpTime}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return ret, err
+ }
+ times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ stat := TimesStat{
+ CPU: "cpu-total",
+ User: float64(times.User) / ClocksPerSec,
+ Nice: float64(times.Nice) / ClocksPerSec,
+ System: float64(times.Sys) / ClocksPerSec,
+ Idle: float64(times.Idle) / ClocksPerSec,
+ Irq: float64(times.Intr) / ClocksPerSec,
+ }
+ return []TimesStat{stat}, nil
+ }
+
+ ncpu, err := unix.SysctlUint32("hw.ncpu")
+ if err != nil {
+ return
+ }
+
+ var i uint32
+ for i = 0; i < ncpu; i++ {
+ mib := []int32{ctlKern, kernCPUStats, int32(i)}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return ret, err
+ }
+
+ stats := (*cpuStats)(unsafe.Pointer(&buf[0]))
+ if (stats.Flags & cpuOnline) == 0 {
+ continue
+ }
+ ret = append(ret, TimesStat{
+ CPU: fmt.Sprintf("cpu%d", i),
+ User: float64(stats.User) / ClocksPerSec,
+ Nice: float64(stats.Nice) / ClocksPerSec,
+ System: float64(stats.Sys) / ClocksPerSec,
+ Idle: float64(stats.Idle) / ClocksPerSec,
+ Irq: float64(stats.Intr) / ClocksPerSec,
+ })
+ }
+
+ return ret, nil
+}
+
+// Returns only one (minimal) CPUInfoStat on OpenBSD
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+ var err error
+
+ c := InfoStat{}
+
+ mhz, err := unix.SysctlUint32("hw.cpuspeed")
+ if err != nil {
+ return nil, err
+ }
+ c.Mhz = float64(mhz)
+
+ ncpu, err := unix.SysctlUint32("hw.ncpuonline")
+ if err != nil {
+ return nil, err
+ }
+ c.Cores = int32(ncpu)
+
+ if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+ return nil, err
+ }
+
+ return append(ret, c), nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go
new file mode 100644
index 0000000..40a6f43
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Spin uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go
new file mode 100644
index 0000000..464156d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Spin uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go
new file mode 100644
index 0000000..40a6f43
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Spin uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go
new file mode 100644
index 0000000..464156d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Spin uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go
new file mode 100644
index 0000000..464156d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Spin uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go
new file mode 100644
index 0000000..bff2e0c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package cpu
+
+import (
+ "context"
+ "os"
+ "runtime"
+
+ stats "github.com/lufia/plan9stats"
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ // BUG: percpu flag is not supported yet.
+ root := os.Getenv("HOST_ROOT")
+ c, err := stats.ReadCPUType(ctx, stats.WithRootDir(root))
+ if err != nil {
+ return nil, err
+ }
+ s, err := stats.ReadCPUStats(ctx, stats.WithRootDir(root))
+ if err != nil {
+ return nil, err
+ }
+ return []TimesStat{
+ {
+ CPU: c.Name,
+ User: s.User.Seconds(),
+ System: s.Sys.Seconds(),
+ Idle: s.Idle.Seconds(),
+ },
+ }, nil
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ return []InfoStat{}, common.ErrNotImplementedError
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go
new file mode 100644
index 0000000..d8ba1d3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "regexp"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/tklauser/go-sysconf"
+)
+
+var ClocksPerSec = float64(128)
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ ClocksPerSec = float64(clkTck)
+ }
+}
+
+// sum all values in a float64 map with float64 keys
+func msum(x map[float64]float64) float64 {
+ total := 0.0
+ for _, y := range x {
+ total += y
+ }
+ return total
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+var kstatSplit = regexp.MustCompile(`[:\s]+`)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/")
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute kstat: %s", err)
+ }
+ cpu := make(map[float64]float64)
+ idle := make(map[float64]float64)
+ user := make(map[float64]float64)
+ kern := make(map[float64]float64)
+ iowt := make(map[float64]float64)
+ // swap := make(map[float64]float64)
+ for _, line := range strings.Split(string(kstatSysOut), "\n") {
+ fields := kstatSplit.Split(line, -1)
+ if fields[0] != "cpu_stat" {
+ continue
+ }
+ cpuNumber, err := strconv.ParseFloat(fields[1], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse cpu number: %s", err)
+ }
+ cpu[cpuNumber] = cpuNumber
+ switch fields[3] {
+ case "idle":
+ idle[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse idle: %s", err)
+ }
+ case "user":
+ user[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse user: %s", err)
+ }
+ case "kernel":
+ kern[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse kernel: %s", err)
+ }
+ case "iowait":
+ iowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse iowait: %s", err)
+ }
+ //not sure how this translates, don't report, add to kernel, something else?
+ /*case "swap":
+ swap[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse swap: %s", err)
+ } */
+ }
+ }
+ ret := make([]TimesStat, 0, len(cpu))
+ if percpu {
+ for _, c := range cpu {
+ ct := &TimesStat{
+ CPU: fmt.Sprintf("cpu%d", int(cpu[c])),
+ Idle: idle[c] / ClocksPerSec,
+ User: user[c] / ClocksPerSec,
+ System: kern[c] / ClocksPerSec,
+ Iowait: iowt[c] / ClocksPerSec,
+ }
+ ret = append(ret, *ct)
+ }
+ } else {
+ ct := &TimesStat{
+ CPU: "cpu-total",
+ Idle: msum(idle) / ClocksPerSec,
+ User: msum(user) / ClocksPerSec,
+ System: msum(kern) / ClocksPerSec,
+ Iowait: msum(iowt) / ClocksPerSec,
+ }
+ ret = append(ret, *ct)
+ }
+ return ret, nil
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ psrInfoOut, err := invoke.CommandWithContext(ctx, "psrinfo", "-p", "-v")
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute psrinfo: %s", err)
+ }
+
+ procs, err := parseProcessorInfo(string(psrInfoOut))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing psrinfo output: %s", err)
+ }
+
+ isaInfoOut, err := invoke.CommandWithContext(ctx, "isainfo", "-b", "-v")
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute isainfo: %s", err)
+ }
+
+ flags, err := parseISAInfo(string(isaInfoOut))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing isainfo output: %s", err)
+ }
+
+ result := make([]InfoStat, 0, len(flags))
+ for _, proc := range procs {
+ procWithFlags := proc
+ procWithFlags.Flags = flags
+ result = append(result, procWithFlags)
+ }
+
+ return result, nil
+}
+
+var flagsMatch = regexp.MustCompile(`[\w\.]+`)
+
+func parseISAInfo(cmdOutput string) ([]string, error) {
+ words := flagsMatch.FindAllString(cmdOutput, -1)
+
+ // Sanity check the output
+ if len(words) < 4 || words[1] != "bit" || words[3] != "applications" {
+ return nil, errors.New("attempted to parse invalid isainfo output")
+ }
+
+ flags := make([]string, len(words)-4)
+ for i, val := range words[4:] {
+ flags[i] = val
+ }
+ sort.Strings(flags)
+
+ return flags, nil
+}
+
+var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processors? \(([\d-]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`)
+
+const (
+ psrNumCoresOffset = 1
+ psrNumCoresHTOffset = 3
+ psrNumHTOffset = 4
+ psrVendorIDOffset = 5
+ psrFamilyOffset = 7
+ psrModelOffset = 8
+ psrStepOffset = 9
+ psrClockOffset = 10
+ psrModelNameOffset = 11
+)
+
+func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
+ matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1)
+
+ var infoStatCount int32
+ result := make([]InfoStat, 0, len(matches))
+ for physicalIndex, physicalCPU := range matches {
+ var step int32
+ var clock float64
+
+ if physicalCPU[psrStepOffset] != "" {
+ stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %s", physicalCPU[9], err)
+ }
+ step = int32(stepParsed)
+ }
+
+ if physicalCPU[psrClockOffset] != "" {
+ clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %s", physicalCPU[10], err)
+ }
+ clock = float64(clockParsed)
+ }
+
+ var err error
+ var numCores int64
+ var numHT int64
+ switch {
+ case physicalCPU[psrNumCoresOffset] != "":
+ numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[1], err)
+ }
+
+ for i := 0; i < int(numCores); i++ {
+ result = append(result, InfoStat{
+ CPU: infoStatCount,
+ PhysicalID: strconv.Itoa(physicalIndex),
+ CoreID: strconv.Itoa(i),
+ Cores: 1,
+ VendorID: physicalCPU[psrVendorIDOffset],
+ ModelName: physicalCPU[psrModelNameOffset],
+ Family: physicalCPU[psrFamilyOffset],
+ Model: physicalCPU[psrModelOffset],
+ Stepping: step,
+ Mhz: clock,
+ })
+ infoStatCount++
+ }
+ case physicalCPU[psrNumCoresHTOffset] != "":
+ numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[3], err)
+ }
+
+ numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %s", physicalCPU[4], err)
+ }
+
+ for i := 0; i < int(numCores); i++ {
+ result = append(result, InfoStat{
+ CPU: infoStatCount,
+ PhysicalID: strconv.Itoa(physicalIndex),
+ CoreID: strconv.Itoa(i),
+ Cores: int32(numHT) / int32(numCores),
+ VendorID: physicalCPU[psrVendorIDOffset],
+ ModelName: physicalCPU[psrModelNameOffset],
+ Family: physicalCPU[psrFamilyOffset],
+ Model: physicalCPU[psrModelOffset],
+ Stepping: step,
+ Mhz: clock,
+ })
+ infoStatCount++
+ }
+ default:
+ return nil, errors.New("values for cores with and without hyperthreading are both set")
+ }
+ }
+ return result, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go
new file mode 100644
index 0000000..4476b91
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/yusufpapurcu/wmi"
+ "golang.org/x/sys/windows"
+)
+
+var procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
+
+type win32_Processor struct {
+ Family uint16
+ Manufacturer string
+ Name string
+ NumberOfLogicalProcessors uint32
+ NumberOfCores uint32
+ ProcessorID *string
+ Stepping *string
+ MaxClockSpeed uint32
+}
+
+// SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
+// defined in windows api doc with the following
+// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntquerysysteminformation#system_processor_performance_information
+// additional fields documented here
+// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/processor_performance.htm
+type win32_SystemProcessorPerformanceInformation struct {
+ IdleTime int64 // idle time in 100ns (this is not a filetime).
+ KernelTime int64 // kernel time in 100ns. kernel time includes idle time. (this is not a filetime).
+ UserTime int64 // usertime in 100ns (this is not a filetime).
+ DpcTime int64 // dpc time in 100ns (this is not a filetime).
+ InterruptTime int64 // interrupt time in 100ns
+ InterruptCount uint32
+}
+
+const (
+ ClocksPerSec = 10000000.0
+
+ // systemProcessorPerformanceInformationClass information class to query with NTQuerySystemInformation
+ // https://processhacker.sourceforge.io/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0
+ win32_SystemProcessorPerformanceInformationClass = 8
+
+ // size of systemProcessorPerformanceInfoSize in memory
+ win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{}))
+)
+
+// Times returns times stat per cpu and combined for all CPUs
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ return perCPUTimes()
+ }
+
+ var ret []TimesStat
+ var lpIdleTime common.FILETIME
+ var lpKernelTime common.FILETIME
+ var lpUserTime common.FILETIME
+ r, _, _ := common.ProcGetSystemTimes.Call(
+ uintptr(unsafe.Pointer(&lpIdleTime)),
+ uintptr(unsafe.Pointer(&lpKernelTime)),
+ uintptr(unsafe.Pointer(&lpUserTime)))
+ if r == 0 {
+ return ret, windows.GetLastError()
+ }
+
+ LOT := float64(0.0000001)
+ HIT := (LOT * 4294967296.0)
+ idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
+ user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
+ kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
+ system := (kernel - idle)
+
+ ret = append(ret, TimesStat{
+ CPU: "cpu-total",
+ Idle: float64(idle),
+ User: float64(user),
+ System: float64(system),
+ })
+ return ret, nil
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+ var dst []win32_Processor
+ q := wmi.CreateQuery(&dst, "")
+ if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
+ return ret, err
+ }
+
+ var procID string
+ for i, l := range dst {
+ procID = ""
+ if l.ProcessorID != nil {
+ procID = *l.ProcessorID
+ }
+
+ cpu := InfoStat{
+ CPU: int32(i),
+ Family: fmt.Sprintf("%d", l.Family),
+ VendorID: l.Manufacturer,
+ ModelName: l.Name,
+ Cores: int32(l.NumberOfLogicalProcessors),
+ PhysicalID: procID,
+ Mhz: float64(l.MaxClockSpeed),
+ Flags: []string{},
+ }
+ ret = append(ret, cpu)
+ }
+
+ return ret, nil
+}
+
+// perCPUTimes returns times stat per cpu, per core and overall for all CPUs
+func perCPUTimes() ([]TimesStat, error) {
+ var ret []TimesStat
+ stats, err := perfInfo()
+ if err != nil {
+ return nil, err
+ }
+ for core, v := range stats {
+ c := TimesStat{
+ CPU: fmt.Sprintf("cpu%d", core),
+ User: float64(v.UserTime) / ClocksPerSec,
+ System: float64(v.KernelTime-v.IdleTime) / ClocksPerSec,
+ Idle: float64(v.IdleTime) / ClocksPerSec,
+ Irq: float64(v.InterruptTime) / ClocksPerSec,
+ }
+ ret = append(ret, c)
+ }
+ return ret, nil
+}
+
+// makes call to Windows API function to retrieve performance information for each core
+func perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) {
+ // Make maxResults large for safety.
+ // We can't invoke the api call with a results array that's too small.
+ // If we have more than 2056 cores on a single host, then it's probably the future.
+ maxBuffer := 2056
+ // buffer for results from the windows proc
+ resultBuffer := make([]win32_SystemProcessorPerformanceInformation, maxBuffer)
+ // size of the buffer in memory
+ bufferSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(maxBuffer)
+ // size of the returned response
+ var retSize uint32
+
+ // Invoke windows api proc.
+ // The returned err from the windows dll proc will always be non-nil even when successful.
+ // See https://godoc.org/golang.org/x/sys/windows#LazyProc.Call for more information
+ retCode, _, err := common.ProcNtQuerySystemInformation.Call(
+ win32_SystemProcessorPerformanceInformationClass, // System Information Class -> SystemProcessorPerformanceInformation
+ uintptr(unsafe.Pointer(&resultBuffer[0])), // pointer to first element in result buffer
+ bufferSize, // size of the buffer in memory
+ uintptr(unsafe.Pointer(&retSize)), // pointer to the size of the returned results the windows proc will set this
+ )
+
+ // check return code for errors
+ if retCode != 0 {
+ return nil, fmt.Errorf("call to NtQuerySystemInformation returned %d. err: %s", retCode, err.Error())
+ }
+
+ // calculate the number of returned elements based on the returned size
+ numReturnedElements := retSize / win32_SystemProcessorPerformanceInfoSize
+
+ // trim results to the number of returned elements
+ resultBuffer = resultBuffer[:numReturnedElements]
+
+ return resultBuffer, nil
+}
+
+// SystemInfo is an equivalent representation of SYSTEM_INFO in the Windows API.
+// https://msdn.microsoft.com/en-us/library/ms724958%28VS.85%29.aspx?f=255&MSPPError=-2147217396
+// https://github.com/elastic/go-windows/blob/bb1581babc04d5cb29a2bfa7a9ac6781c730c8dd/kernel32.go#L43
+type systemInfo struct {
+ wProcessorArchitecture uint16
+ wReserved uint16
+ dwPageSize uint32
+ lpMinimumApplicationAddress uintptr
+ lpMaximumApplicationAddress uintptr
+ dwActiveProcessorMask uintptr
+ dwNumberOfProcessors uint32
+ dwProcessorType uint32
+ dwAllocationGranularity uint32
+ wProcessorLevel uint16
+ wProcessorRevision uint16
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ if logical {
+ // https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L97
+ ret := windows.GetActiveProcessorCount(windows.ALL_PROCESSOR_GROUPS)
+ if ret != 0 {
+ return int(ret), nil
+ }
+ var systemInfo systemInfo
+ _, _, err := procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
+ if systemInfo.dwNumberOfProcessors == 0 {
+ return 0, err
+ }
+ return int(systemInfo.dwNumberOfProcessors), nil
+ }
+ // physical cores https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499
+ // for the time being, try with unreliable and slow WMI call…
+ var dst []win32_Processor
+ q := wmi.CreateQuery(&dst, "")
+ if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
+ return 0, err
+ }
+ var count uint32
+ for _, d := range dst {
+ count += d.NumberOfCores
+ }
+ return int(count), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/binary.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/binary.go
new file mode 100644
index 0000000..6e75e74
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/binary.go
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package binary implements simple translation between numbers and byte
+// sequences and encoding and decoding of varints.
+//
+// Numbers are translated by reading and writing fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+//
+// The varint functions encode and decode single integer values using
+// a variable-length encoding; smaller values require fewer bytes.
+// For a specification, see
+// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
+//
+// This package favors simplicity over efficiency. Clients that require
+// high-performance serialization, especially for large data structures,
+// should look at more advanced solutions such as the encoding/gob
+// package or protocol buffers.
+
+import (
+ "errors"
+ "io"
+ "math"
+ "reflect"
+)
+
+// A ByteOrder specifies how to convert byte sequences into
+// 16-, 32-, or 64-bit unsigned integers.
+type ByteOrder interface {
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ Uint64([]byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]byte, uint64)
+ String() string
+}
+
+// LittleEndian is the little-endian implementation of ByteOrder.
+var LittleEndian littleEndian
+
+// BigEndian is the big-endian implementation of ByteOrder.
+var BigEndian bigEndian
+
+type littleEndian struct{}
+
+func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+
+func (littleEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (littleEndian) Uint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (littleEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (littleEndian) Uint64(b []byte) uint64 {
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (littleEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
+
+func (littleEndian) String() string { return "LittleEndian" }
+
+func (littleEndian) GoString() string { return "binary.LittleEndian" }
+
+type bigEndian struct{}
+
+func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+
+func (bigEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func (bigEndian) Uint32(b []byte) uint32 {
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (bigEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func (bigEndian) Uint64(b []byte) uint64 {
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func (bigEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v >> 56)
+ b[1] = byte(v >> 48)
+ b[2] = byte(v >> 40)
+ b[3] = byte(v >> 32)
+ b[4] = byte(v >> 24)
+ b[5] = byte(v >> 16)
+ b[6] = byte(v >> 8)
+ b[7] = byte(v)
+}
+
+func (bigEndian) String() string { return "BigEndian" }
+
+func (bigEndian) GoString() string { return "binary.BigEndian" }
+
+// Read reads structured binary data from r into data.
+// Data must be a pointer to a fixed-size value or a slice
+// of fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
+// When reading into structs, the field data for fields with
+// blank (_) field names is skipped; i.e., blank field names
+// may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
+func Read(r io.Reader, order ByteOrder, data interface{}) error {
+ // Fast path for basic types and slices.
+ if n := intDataSize(data); n != 0 {
+ var b [8]byte
+ var bs []byte
+ if n > len(b) {
+ bs = make([]byte, n)
+ } else {
+ bs = b[:n]
+ }
+ if _, err := io.ReadFull(r, bs); err != nil {
+ return err
+ }
+ switch data := data.(type) {
+ case *int8:
+ *data = int8(b[0])
+ case *uint8:
+ *data = b[0]
+ case *int16:
+ *data = int16(order.Uint16(bs))
+ case *uint16:
+ *data = order.Uint16(bs)
+ case *int32:
+ *data = int32(order.Uint32(bs))
+ case *uint32:
+ *data = order.Uint32(bs)
+ case *int64:
+ *data = int64(order.Uint64(bs))
+ case *uint64:
+ *data = order.Uint64(bs)
+ case []int8:
+ for i, x := range bs { // Easier to loop over the input for 8-bit values.
+ data[i] = int8(x)
+ }
+ case []uint8:
+ copy(data, bs)
+ case []int16:
+ for i := range data {
+ data[i] = int16(order.Uint16(bs[2*i:]))
+ }
+ case []uint16:
+ for i := range data {
+ data[i] = order.Uint16(bs[2*i:])
+ }
+ case []int32:
+ for i := range data {
+ data[i] = int32(order.Uint32(bs[4*i:]))
+ }
+ case []uint32:
+ for i := range data {
+ data[i] = order.Uint32(bs[4*i:])
+ }
+ case []int64:
+ for i := range data {
+ data[i] = int64(order.Uint64(bs[8*i:]))
+ }
+ case []uint64:
+ for i := range data {
+ data[i] = order.Uint64(bs[8*i:])
+ }
+ }
+ return nil
+ }
+
+ // Fallback to reflect-based decoding.
+ v := reflect.ValueOf(data)
+ size := -1
+ switch v.Kind() {
+ case reflect.Ptr:
+ v = v.Elem()
+ size = dataSize(v)
+ case reflect.Slice:
+ size = dataSize(v)
+ }
+ if size < 0 {
+ return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
+ }
+ d := &decoder{order: order, buf: make([]byte, size)}
+ if _, err := io.ReadFull(r, d.buf); err != nil {
+ return err
+ }
+ d.value(v)
+ return nil
+}
+
+// Write writes the binary representation of data into w.
+// Data must be a fixed-size value or a slice of fixed-size
+// values, or a pointer to such data.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
+// When writing structs, zero values are written for fields
+// with blank (_) field names.
+func Write(w io.Writer, order ByteOrder, data interface{}) error {
+ // Fast path for basic types and slices.
+ if n := intDataSize(data); n != 0 {
+ var b [8]byte
+ var bs []byte
+ if n > len(b) {
+ bs = make([]byte, n)
+ } else {
+ bs = b[:n]
+ }
+ switch v := data.(type) {
+ case *int8:
+ bs = b[:1]
+ b[0] = byte(*v)
+ case int8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case []int8:
+ for i, x := range v {
+ bs[i] = byte(x)
+ }
+ case *uint8:
+ bs = b[:1]
+ b[0] = *v
+ case uint8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case []uint8:
+ bs = v
+ case *int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(*v))
+ case int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(v))
+ case []int16:
+ for i, x := range v {
+ order.PutUint16(bs[2*i:], uint16(x))
+ }
+ case *uint16:
+ bs = b[:2]
+ order.PutUint16(bs, *v)
+ case uint16:
+ bs = b[:2]
+ order.PutUint16(bs, v)
+ case []uint16:
+ for i, x := range v {
+ order.PutUint16(bs[2*i:], x)
+ }
+ case *int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(*v))
+ case int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(v))
+ case []int32:
+ for i, x := range v {
+ order.PutUint32(bs[4*i:], uint32(x))
+ }
+ case *uint32:
+ bs = b[:4]
+ order.PutUint32(bs, *v)
+ case uint32:
+ bs = b[:4]
+ order.PutUint32(bs, v)
+ case []uint32:
+ for i, x := range v {
+ order.PutUint32(bs[4*i:], x)
+ }
+ case *int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(*v))
+ case int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(v))
+ case []int64:
+ for i, x := range v {
+ order.PutUint64(bs[8*i:], uint64(x))
+ }
+ case *uint64:
+ bs = b[:8]
+ order.PutUint64(bs, *v)
+ case uint64:
+ bs = b[:8]
+ order.PutUint64(bs, v)
+ case []uint64:
+ for i, x := range v {
+ order.PutUint64(bs[8*i:], x)
+ }
+ }
+ _, err := w.Write(bs)
+ return err
+ }
+
+ // Fallback to reflect-based encoding.
+ v := reflect.Indirect(reflect.ValueOf(data))
+ size := dataSize(v)
+ if size < 0 {
+ return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String())
+ }
+ buf := make([]byte, size)
+ e := &encoder{order: order, buf: buf}
+ e.value(v)
+ _, err := w.Write(buf)
+ return err
+}
+
+// Size returns how many bytes Write would generate to encode the value v, which
+// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
+// If v is neither of these, Size returns -1.
+func Size(v interface{}) int {
+ return dataSize(reflect.Indirect(reflect.ValueOf(v)))
+}
+
+// dataSize returns the number of bytes the actual data represented by v occupies in memory.
+// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
+// it returns the length of the slice times the element size and does not count the memory
+// occupied by the header. If the type of v is not acceptable, dataSize returns -1.
+func dataSize(v reflect.Value) int {
+ if v.Kind() == reflect.Slice {
+ if s := sizeof(v.Type().Elem()); s >= 0 {
+ return s * v.Len()
+ }
+ return -1
+ }
+ return sizeof(v.Type())
+}
+
+// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
+func sizeof(t reflect.Type) int {
+ switch t.Kind() {
+ case reflect.Array:
+ if s := sizeof(t.Elem()); s >= 0 {
+ return s * t.Len()
+ }
+
+ case reflect.Struct:
+ sum := 0
+ for i, n := 0, t.NumField(); i < n; i++ {
+ s := sizeof(t.Field(i).Type)
+ if s < 0 {
+ return -1
+ }
+ sum += s
+ }
+ return sum
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Ptr:
+ return int(t.Size())
+ }
+
+ return -1
+}
+
+type coder struct {
+ order ByteOrder
+ buf []byte
+}
+
+type (
+ decoder coder
+ encoder coder
+)
+
+func (d *decoder) uint8() uint8 {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x
+}
+
+func (e *encoder) uint8(x uint8) {
+ e.buf[0] = x
+ e.buf = e.buf[1:]
+}
+
+func (d *decoder) uint16() uint16 {
+ x := d.order.Uint16(d.buf[0:2])
+ d.buf = d.buf[2:]
+ return x
+}
+
+func (e *encoder) uint16(x uint16) {
+ e.order.PutUint16(e.buf[0:2], x)
+ e.buf = e.buf[2:]
+}
+
+func (d *decoder) uint32() uint32 {
+ x := d.order.Uint32(d.buf[0:4])
+ d.buf = d.buf[4:]
+ return x
+}
+
+func (e *encoder) uint32(x uint32) {
+ e.order.PutUint32(e.buf[0:4], x)
+ e.buf = e.buf[4:]
+}
+
+func (d *decoder) uint64() uint64 {
+ x := d.order.Uint64(d.buf[0:8])
+ d.buf = d.buf[8:]
+ return x
+}
+
+func (e *encoder) uint64(x uint64) {
+ e.order.PutUint64(e.buf[0:8], x)
+ e.buf = e.buf[8:]
+}
+
+func (d *decoder) int8() int8 { return int8(d.uint8()) }
+
+func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
+
+func (d *decoder) int16() int16 { return int16(d.uint16()) }
+
+func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
+
+func (d *decoder) int32() int32 { return int32(d.uint32()) }
+
+func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
+
+func (d *decoder) int64() int64 { return int64(d.uint64()) }
+
+func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
+
+func (d *decoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+
+ case reflect.Struct:
+ t := v.Type()
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ // Note: Calling v.CanSet() below is an optimization.
+ // It would be sufficient to check the field name,
+ // but creating the StructField info for each field is
+ // costly (run "go test -bench=ReadStruct" and compare
+ // results when making changes to this code).
+ if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
+ d.value(v)
+ } else {
+ d.skip(v)
+ }
+ }
+
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+
+ case reflect.Int8:
+ v.SetInt(int64(d.int8()))
+ case reflect.Int16:
+ v.SetInt(int64(d.int16()))
+ case reflect.Int32:
+ v.SetInt(int64(d.int32()))
+ case reflect.Int64:
+ v.SetInt(d.int64())
+
+ case reflect.Uint8:
+ v.SetUint(uint64(d.uint8()))
+ case reflect.Uint16:
+ v.SetUint(uint64(d.uint16()))
+ case reflect.Uint32:
+ v.SetUint(uint64(d.uint32()))
+ case reflect.Uint64:
+ v.SetUint(d.uint64())
+
+ case reflect.Float32:
+ v.SetFloat(float64(math.Float32frombits(d.uint32())))
+ case reflect.Float64:
+ v.SetFloat(math.Float64frombits(d.uint64()))
+
+ case reflect.Complex64:
+ v.SetComplex(complex(
+ float64(math.Float32frombits(d.uint32())),
+ float64(math.Float32frombits(d.uint32())),
+ ))
+ case reflect.Complex128:
+ v.SetComplex(complex(
+ math.Float64frombits(d.uint64()),
+ math.Float64frombits(d.uint64()),
+ ))
+ }
+}
+
+func (e *encoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+
+ case reflect.Struct:
+ t := v.Type()
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ // see comment for corresponding code in decoder.value()
+ if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
+ e.value(v)
+ } else {
+ e.skip(v)
+ }
+ }
+
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ switch v.Type().Kind() {
+ case reflect.Int8:
+ e.int8(int8(v.Int()))
+ case reflect.Int16:
+ e.int16(int16(v.Int()))
+ case reflect.Int32:
+ e.int32(int32(v.Int()))
+ case reflect.Int64:
+ e.int64(v.Int())
+ }
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ switch v.Type().Kind() {
+ case reflect.Uint8:
+ e.uint8(uint8(v.Uint()))
+ case reflect.Uint16:
+ e.uint16(uint16(v.Uint()))
+ case reflect.Uint32:
+ e.uint32(uint32(v.Uint()))
+ case reflect.Uint64:
+ e.uint64(v.Uint())
+ }
+
+ case reflect.Float32, reflect.Float64:
+ switch v.Type().Kind() {
+ case reflect.Float32:
+ e.uint32(math.Float32bits(float32(v.Float())))
+ case reflect.Float64:
+ e.uint64(math.Float64bits(v.Float()))
+ }
+
+ case reflect.Complex64, reflect.Complex128:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ x := v.Complex()
+ e.uint32(math.Float32bits(float32(real(x))))
+ e.uint32(math.Float32bits(float32(imag(x))))
+ case reflect.Complex128:
+ x := v.Complex()
+ e.uint64(math.Float64bits(real(x)))
+ e.uint64(math.Float64bits(imag(x)))
+ }
+ }
+}
+
+func (d *decoder) skip(v reflect.Value) {
+ d.buf = d.buf[dataSize(v):]
+}
+
+func (e *encoder) skip(v reflect.Value) {
+ n := dataSize(v)
+ for i := range e.buf[0:n] {
+ e.buf[i] = 0
+ }
+ e.buf = e.buf[n:]
+}
+
+// intDataSize returns the size of the data required to represent the data when encoded.
+// It returns zero if the type cannot be implemented by the fast path in Read or Write.
+func intDataSize(data interface{}) int {
+ switch data := data.(type) {
+ case int8, *int8, *uint8:
+ return 1
+ case []int8:
+ return len(data)
+ case []uint8:
+ return len(data)
+ case int16, *int16, *uint16:
+ return 2
+ case []int16:
+ return 2 * len(data)
+ case []uint16:
+ return 2 * len(data)
+ case int32, *int32, *uint32:
+ return 4
+ case []int32:
+ return 4 * len(data)
+ case []uint32:
+ return 4 * len(data)
+ case int64, *int64, *uint64:
+ return 8
+ case []int64:
+ return 8 * len(data)
+ case []uint64:
+ return 8 * len(data)
+ }
+ return 0
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go
new file mode 100644
index 0000000..868ea4d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+//
+// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
+// This covers these architectures.
+// - linux (amd64, arm)
+// - freebsd (amd64)
+// - windows (amd64)
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "net/url"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/shirou/gopsutil/v4/common"
+)
+
+var (
+ Timeout = 3 * time.Second
+ ErrTimeout = errors.New("command timed out")
+)
+
+type Invoker interface {
+ Command(string, ...string) ([]byte, error)
+ CommandWithContext(context.Context, string, ...string) ([]byte, error)
+}
+
+type Invoke struct{}
+
+func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), Timeout)
+ defer cancel()
+ return i.CommandWithContext(ctx, name, arg...)
+}
+
+func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
+ cmd := exec.CommandContext(ctx, name, arg...)
+
+ var buf bytes.Buffer
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+
+ if err := cmd.Start(); err != nil {
+ return buf.Bytes(), err
+ }
+
+ if err := cmd.Wait(); err != nil {
+ return buf.Bytes(), err
+ }
+
+ return buf.Bytes(), nil
+}
+
+type FakeInvoke struct {
+ Suffix string // Suffix species expected file name suffix such as "fail"
+ Error error // If Error specified, return the error.
+}
+
+// Command in FakeInvoke returns from expected file if exists.
+func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
+ if i.Error != nil {
+ return []byte{}, i.Error
+ }
+
+ arch := runtime.GOOS
+
+ commandName := filepath.Base(name)
+
+ fname := strings.Join(append([]string{commandName}, arg...), "")
+ fname = url.QueryEscape(fname)
+ fpath := path.Join("testdata", arch, fname)
+ if i.Suffix != "" {
+ fpath += "_" + i.Suffix
+ }
+ if PathExists(fpath) {
+ return os.ReadFile(fpath)
+ }
+ return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
+}
+
+func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
+ return i.Command(name, arg...)
+}
+
+var ErrNotImplementedError = errors.New("not implemented yet")
+
+// ReadFile reads contents from a file
+func ReadFile(filename string) (string, error) {
+ content, err := os.ReadFile(filename)
+ if err != nil {
+ return "", err
+ }
+
+ return string(content), nil
+}
+
+// ReadLines reads contents from a file and splits them by new lines.
+// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
+func ReadLines(filename string) ([]string, error) {
+ return ReadLinesOffsetN(filename, 0, -1)
+}
+
+// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix.
+func ReadLine(filename string, prefix string) (string, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ r := bufio.NewReader(f)
+ for {
+ line, err := r.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return "", err
+ }
+ if strings.HasPrefix(line, prefix) {
+ return line, nil
+ }
+ }
+
+ return "", nil
+}
+
+// ReadLinesOffsetN reads contents from file and splits them by new line.
+// The offset tells at which line number to start.
+// The count determines the number of lines to read (starting from offset):
+// n >= 0: at most n lines
+// n < 0: whole file
+func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return []string{""}, err
+ }
+ defer f.Close()
+
+ var ret []string
+
+ r := bufio.NewReader(f)
+ for i := uint(0); i < uint(n)+offset || n < 0; i++ {
+ line, err := r.ReadString('\n')
+ if err != nil {
+ if err == io.EOF && len(line) > 0 {
+ ret = append(ret, strings.Trim(line, "\n"))
+ }
+ break
+ }
+ if i < offset {
+ continue
+ }
+ ret = append(ret, strings.Trim(line, "\n"))
+ }
+
+ return ret, nil
+}
+
+func IntToString(orig []int8) string {
+ ret := make([]byte, len(orig))
+ size := -1
+ for i, o := range orig {
+ if o == 0 {
+ size = i
+ break
+ }
+ ret[i] = byte(o)
+ }
+ if size == -1 {
+ size = len(orig)
+ }
+
+ return string(ret[0:size])
+}
+
+func UintToString(orig []uint8) string {
+ ret := make([]byte, len(orig))
+ size := -1
+ for i, o := range orig {
+ if o == 0 {
+ size = i
+ break
+ }
+ ret[i] = byte(o)
+ }
+ if size == -1 {
+ size = len(orig)
+ }
+
+ return string(ret[0:size])
+}
+
+func ByteToString(orig []byte) string {
+ n := -1
+ l := -1
+ for i, b := range orig {
+ // skip left side null
+ if l == -1 && b == 0 {
+ continue
+ }
+ if l == -1 {
+ l = i
+ }
+
+ if b == 0 {
+ break
+ }
+ n = i + 1
+ }
+ if n == -1 {
+ return string(orig)
+ }
+ return string(orig[l:n])
+}
+
+// ReadInts reads contents from single line file and returns them as []int32.
+func ReadInts(filename string) ([]int64, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return []int64{}, err
+ }
+ defer f.Close()
+
+ var ret []int64
+
+ r := bufio.NewReader(f)
+
+ // The int files that this is concerned with should only be one liners.
+ line, err := r.ReadString('\n')
+ if err != nil {
+ return []int64{}, err
+ }
+
+ i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
+ if err != nil {
+ return []int64{}, err
+ }
+ ret = append(ret, i)
+
+ return ret, nil
+}
+
+// Parse Hex to uint32 without error
+func HexToUint32(hex string) uint32 {
+ vv, _ := strconv.ParseUint(hex, 16, 32)
+ return uint32(vv)
+}
+
+// Parse to int32 without error
+func mustParseInt32(val string) int32 {
+ vv, _ := strconv.ParseInt(val, 10, 32)
+ return int32(vv)
+}
+
+// Parse to uint64 without error
+func mustParseUint64(val string) uint64 {
+ vv, _ := strconv.ParseInt(val, 10, 64)
+ return uint64(vv)
+}
+
+// Parse to Float64 without error
+func mustParseFloat64(val string) float64 {
+ vv, _ := strconv.ParseFloat(val, 64)
+ return vv
+}
+
+// StringsHas checks the target string slice contains src or not
+func StringsHas(target []string, src string) bool {
+ for _, t := range target {
+ if strings.TrimSpace(t) == src {
+ return true
+ }
+ }
+ return false
+}
+
+// StringsContains checks the src in any string of the target string slice
+func StringsContains(target []string, src string) bool {
+ for _, t := range target {
+ if strings.Contains(t, src) {
+ return true
+ }
+ }
+ return false
+}
+
+// IntContains checks the src in any int of the target int slice.
+func IntContains(target []int, src int) bool {
+ for _, t := range target {
+ if src == t {
+ return true
+ }
+ }
+ return false
+}
+
+// get struct attributes.
+// This method is used only for debugging platform dependent code.
+func attributes(m interface{}) map[string]reflect.Type {
+ typ := reflect.TypeOf(m)
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ }
+
+ attrs := make(map[string]reflect.Type)
+ if typ.Kind() != reflect.Struct {
+ return nil
+ }
+
+ for i := 0; i < typ.NumField(); i++ {
+ p := typ.Field(i)
+ if !p.Anonymous {
+ attrs[p.Name] = p.Type
+ }
+ }
+
+ return attrs
+}
+
+func PathExists(filename string) bool {
+ if _, err := os.Stat(filename); err == nil {
+ return true
+ }
+ return false
+}
+
+// PathExistsWithContents returns the filename exists and it is not empty
+func PathExistsWithContents(filename string) bool {
+ info, err := os.Stat(filename)
+ if err != nil {
+ return false
+ }
+ return info.Size() > 4 && !info.IsDir() // at least 4 bytes
+}
+
+// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default.
+// The context may optionally contain a map superseding os.EnvKey.
+func GetEnvWithContext(ctx context.Context, key string, dfault string, combineWith ...string) string {
+ var value string
+ if env, ok := ctx.Value(common.EnvKey).(common.EnvMap); ok {
+ value = env[common.EnvKeyType(key)]
+ }
+ if value == "" {
+ value = os.Getenv(key)
+ }
+ if value == "" {
+ value = dfault
+ }
+
+ return combine(value, combineWith)
+}
+
+// GetEnv retrieves the environment variable key. If it does not exist it returns the default.
+func GetEnv(key string, dfault string, combineWith ...string) string {
+ value := os.Getenv(key)
+ if value == "" {
+ value = dfault
+ }
+
+ return combine(value, combineWith)
+}
+
+func combine(value string, combineWith []string) string {
+ switch len(combineWith) {
+ case 0:
+ return value
+ case 1:
+ return filepath.Join(value, combineWith[0])
+ default:
+ all := make([]string, len(combineWith)+1)
+ all[0] = value
+ copy(all[1:], combineWith)
+ return filepath.Join(all...)
+ }
+}
+
+func HostProc(combineWith ...string) string {
+ return GetEnv("HOST_PROC", "/proc", combineWith...)
+}
+
+func HostSys(combineWith ...string) string {
+ return GetEnv("HOST_SYS", "/sys", combineWith...)
+}
+
+func HostEtc(combineWith ...string) string {
+ return GetEnv("HOST_ETC", "/etc", combineWith...)
+}
+
+func HostVar(combineWith ...string) string {
+ return GetEnv("HOST_VAR", "/var", combineWith...)
+}
+
+func HostRun(combineWith ...string) string {
+ return GetEnv("HOST_RUN", "/run", combineWith...)
+}
+
+func HostDev(combineWith ...string) string {
+ return GetEnv("HOST_DEV", "/dev", combineWith...)
+}
+
+func HostRoot(combineWith ...string) string {
+ return GetEnv("HOST_ROOT", "/", combineWith...)
+}
+
+func HostProcWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_PROC", "/proc", combineWith...)
+}
+
+func HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_PROC_MOUNTINFO", "", combineWith...)
+}
+
+func HostSysWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_SYS", "/sys", combineWith...)
+}
+
+func HostEtcWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_ETC", "/etc", combineWith...)
+}
+
+func HostVarWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_VAR", "/var", combineWith...)
+}
+
+func HostRunWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_RUN", "/run", combineWith...)
+}
+
+func HostDevWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_DEV", "/dev", combineWith...)
+}
+
+func HostRootWithContext(ctx context.Context, combineWith ...string) string {
+ return GetEnvWithContext(ctx, "HOST_ROOT", "/", combineWith...)
+}
+
+// getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
+// sysctl commands (see DoSysctrl).
+func getSysctrlEnv(env []string) []string {
+ foundLC := false
+ for i, line := range env {
+ if strings.HasPrefix(line, "LC_ALL") {
+ env[i] = "LC_ALL=C"
+ foundLC = true
+ }
+ }
+ if !foundLC {
+ env = append(env, "LC_ALL=C")
+ }
+ return env
+}
+
+// Round places rounds the number 'val' to 'n' decimal places
+func Round(val float64, n int) float64 {
+ // Calculate the power of 10 to the n
+ pow10 := math.Pow(10, float64(n))
+ // Multiply the value by pow10, round it, then divide it by pow10
+ return math.Round(val*pow10) / pow10
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go
new file mode 100644
index 0000000..2de3bb1
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package common
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "github.com/ebitengine/purego"
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrlWithContext(ctx context.Context, mib string) ([]string, error) {
+ cmd := exec.CommandContext(ctx, "sysctl", "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146
+ uintptr(unsafe.Pointer(&mib[0])),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146
+ uintptr(unsafe.Pointer(&mib[0])),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
+
+// Library represents a dynamic library loaded by purego.
+type Library struct {
+ addr uintptr
+ path string
+ close func()
+}
+
+// library paths
+const (
+ IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit"
+ CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"
+ System = "/usr/lib/libSystem.B.dylib"
+)
+
+func NewLibrary(path string) (*Library, error) {
+ lib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
+ if err != nil {
+ return nil, err
+ }
+
+ closeFunc := func() {
+ purego.Dlclose(lib)
+ }
+
+ return &Library{
+ addr: lib,
+ path: path,
+ close: closeFunc,
+ }, nil
+}
+
+func (lib *Library) Dlsym(symbol string) (uintptr, error) {
+ return purego.Dlsym(lib.addr, symbol)
+}
+
+func GetFunc[T any](lib *Library, symbol string) T {
+ var fptr T
+ purego.RegisterLibFunc(&fptr, lib.addr, symbol)
+ return fptr
+}
+
+func (lib *Library) Close() {
+ lib.close()
+}
+
+// status codes
+const (
+ KERN_SUCCESS = 0
+)
+
+// IOKit functions and symbols.
+type (
+ IOServiceGetMatchingServiceFunc func(mainPort uint32, matching uintptr) uint32
+ IOServiceGetMatchingServicesFunc func(mainPort uint32, matching uintptr, existing *uint32) int
+ IOServiceMatchingFunc func(name string) unsafe.Pointer
+ IOServiceOpenFunc func(service, owningTask, connType uint32, connect *uint32) int
+ IOServiceCloseFunc func(connect uint32) int
+ IOIteratorNextFunc func(iterator uint32) uint32
+ IORegistryEntryGetNameFunc func(entry uint32, name CStr) int
+ IORegistryEntryGetParentEntryFunc func(entry uint32, plane string, parent *uint32) int
+ IORegistryEntryCreateCFPropertyFunc func(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer
+ IORegistryEntryCreateCFPropertiesFunc func(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int
+ IOObjectConformsToFunc func(object uint32, className string) bool
+ IOObjectReleaseFunc func(object uint32) int
+ IOConnectCallStructMethodFunc func(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int
+
+ IOHIDEventSystemClientCreateFunc func(allocator uintptr) unsafe.Pointer
+ IOHIDEventSystemClientSetMatchingFunc func(client, match uintptr) int
+ IOHIDServiceClientCopyEventFunc func(service uintptr, eventType int64,
+ options int32, timeout int64) unsafe.Pointer
+ IOHIDServiceClientCopyPropertyFunc func(service, property uintptr) unsafe.Pointer
+ IOHIDEventGetFloatValueFunc func(event uintptr, field int32) float64
+ IOHIDEventSystemClientCopyServicesFunc func(client uintptr) unsafe.Pointer
+)
+
+const (
+ IOServiceGetMatchingServiceSym = "IOServiceGetMatchingService"
+ IOServiceGetMatchingServicesSym = "IOServiceGetMatchingServices"
+ IOServiceMatchingSym = "IOServiceMatching"
+ IOServiceOpenSym = "IOServiceOpen"
+ IOServiceCloseSym = "IOServiceClose"
+ IOIteratorNextSym = "IOIteratorNext"
+ IORegistryEntryGetNameSym = "IORegistryEntryGetName"
+ IORegistryEntryGetParentEntrySym = "IORegistryEntryGetParentEntry"
+ IORegistryEntryCreateCFPropertySym = "IORegistryEntryCreateCFProperty"
+ IORegistryEntryCreateCFPropertiesSym = "IORegistryEntryCreateCFProperties"
+ IOObjectConformsToSym = "IOObjectConformsTo"
+ IOObjectReleaseSym = "IOObjectRelease"
+ IOConnectCallStructMethodSym = "IOConnectCallStructMethod"
+
+ IOHIDEventSystemClientCreateSym = "IOHIDEventSystemClientCreate"
+ IOHIDEventSystemClientSetMatchingSym = "IOHIDEventSystemClientSetMatching"
+ IOHIDServiceClientCopyEventSym = "IOHIDServiceClientCopyEvent"
+ IOHIDServiceClientCopyPropertySym = "IOHIDServiceClientCopyProperty"
+ IOHIDEventGetFloatValueSym = "IOHIDEventGetFloatValue"
+ IOHIDEventSystemClientCopyServicesSym = "IOHIDEventSystemClientCopyServices"
+)
+
+const (
+ KIOMainPortDefault = 0
+
+ KIOHIDEventTypeTemperature = 15
+
+ KNilOptions = 0
+)
+
+const (
+ KIOMediaWholeKey = "Media"
+ KIOServicePlane = "IOService"
+)
+
+// CoreFoundation functions and symbols.
+type (
+ CFGetTypeIDFunc func(cf uintptr) int32
+ CFNumberCreateFunc func(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer
+ CFNumberGetValueFunc func(num uintptr, theType int32, valuePtr uintptr) bool
+ CFDictionaryCreateFunc func(allocator uintptr, keys, values *unsafe.Pointer, numValues int32,
+ keyCallBacks, valueCallBacks uintptr) unsafe.Pointer
+ CFDictionaryAddValueFunc func(theDict, key, value uintptr)
+ CFDictionaryGetValueFunc func(theDict, key uintptr) unsafe.Pointer
+ CFArrayGetCountFunc func(theArray uintptr) int32
+ CFArrayGetValueAtIndexFunc func(theArray uintptr, index int32) unsafe.Pointer
+ CFStringCreateMutableFunc func(alloc uintptr, maxLength int32) unsafe.Pointer
+ CFStringGetLengthFunc func(theString uintptr) int32
+ CFStringGetCStringFunc func(theString uintptr, buffer CStr, bufferSize int32, encoding uint32)
+ CFStringCreateWithCStringFunc func(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer
+ CFDataGetLengthFunc func(theData uintptr) int32
+ CFDataGetBytePtrFunc func(theData uintptr) unsafe.Pointer
+ CFReleaseFunc func(cf uintptr)
+)
+
+const (
+ CFGetTypeIDSym = "CFGetTypeID"
+ CFNumberCreateSym = "CFNumberCreate"
+ CFNumberGetValueSym = "CFNumberGetValue"
+ CFDictionaryCreateSym = "CFDictionaryCreate"
+ CFDictionaryAddValueSym = "CFDictionaryAddValue"
+ CFDictionaryGetValueSym = "CFDictionaryGetValue"
+ CFArrayGetCountSym = "CFArrayGetCount"
+ CFArrayGetValueAtIndexSym = "CFArrayGetValueAtIndex"
+ CFStringCreateMutableSym = "CFStringCreateMutable"
+ CFStringGetLengthSym = "CFStringGetLength"
+ CFStringGetCStringSym = "CFStringGetCString"
+ CFStringCreateWithCStringSym = "CFStringCreateWithCString"
+ CFDataGetLengthSym = "CFDataGetLength"
+ CFDataGetBytePtrSym = "CFDataGetBytePtr"
+ CFReleaseSym = "CFRelease"
+)
+
+const (
+ KCFStringEncodingUTF8 = 0x08000100
+ KCFNumberSInt64Type = 4
+ KCFNumberIntType = 9
+ KCFAllocatorDefault = 0
+)
+
+// Kernel functions and symbols.
+type MachTimeBaseInfo struct {
+ Numer uint32
+ Denom uint32
+}
+
+type (
+ HostProcessorInfoFunc func(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr,
+ outProcessorInfoCnt *uint32) int
+ HostStatisticsFunc func(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int
+ MachHostSelfFunc func() uint32
+ MachTaskSelfFunc func() uint32
+ MachTimeBaseInfoFunc func(info uintptr) int
+ VMDeallocateFunc func(targetTask uint32, vmAddress, vmSize uintptr) int
+)
+
+const (
+ HostProcessorInfoSym = "host_processor_info"
+ HostStatisticsSym = "host_statistics"
+ MachHostSelfSym = "mach_host_self"
+ MachTaskSelfSym = "mach_task_self"
+ MachTimeBaseInfoSym = "mach_timebase_info"
+ VMDeallocateSym = "vm_deallocate"
+)
+
+const (
+ CTL_KERN = 1
+ KERN_ARGMAX = 8
+ KERN_PROCARGS2 = 49
+
+ HOST_VM_INFO = 2
+ HOST_CPU_LOAD_INFO = 3
+
+ HOST_VM_INFO_COUNT = 0xf
+)
+
+// System functions and symbols.
+type (
+ ProcPidPathFunc func(pid int32, buffer uintptr, bufferSize uint32) int32
+ ProcPidInfoFunc func(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32
+)
+
+const (
+ SysctlSym = "sysctl"
+ ProcPidPathSym = "proc_pidpath"
+ ProcPidInfoSym = "proc_pidinfo"
+)
+
+const (
+ MAXPATHLEN = 1024
+ PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN
+ PROC_PIDTASKINFO = 4
+ PROC_PIDVNODEPATHINFO = 9
+)
+
+// SMC represents a SMC instance.
+type SMC struct {
+ lib *Library
+ conn uint32
+ callStruct IOConnectCallStructMethodFunc
+}
+
+const ioServiceSMC = "AppleSMC"
+
+const (
+ KSMCUserClientOpen = 0
+ KSMCUserClientClose = 1
+ KSMCHandleYPCEvent = 2
+ KSMCReadKey = 5
+ KSMCWriteKey = 6
+ KSMCGetKeyCount = 7
+ KSMCGetKeyFromIndex = 8
+ KSMCGetKeyInfo = 9
+)
+
+const (
+ KSMCSuccess = 0
+ KSMCError = 1
+ KSMCKeyNotFound = 132
+)
+
+func NewSMC(ioKit *Library) (*SMC, error) {
+ if ioKit.path != IOKit {
+ return nil, fmt.Errorf("library is not IOKit")
+ }
+
+ ioServiceGetMatchingService := GetFunc[IOServiceGetMatchingServiceFunc](ioKit, IOServiceGetMatchingServiceSym)
+ ioServiceMatching := GetFunc[IOServiceMatchingFunc](ioKit, IOServiceMatchingSym)
+ ioServiceOpen := GetFunc[IOServiceOpenFunc](ioKit, IOServiceOpenSym)
+ ioObjectRelease := GetFunc[IOObjectReleaseFunc](ioKit, IOObjectReleaseSym)
+ machTaskSelf := GetFunc[MachTaskSelfFunc](ioKit, MachTaskSelfSym)
+
+ ioConnectCallStructMethod := GetFunc[IOConnectCallStructMethodFunc](ioKit, IOConnectCallStructMethodSym)
+
+ service := ioServiceGetMatchingService(0, uintptr(ioServiceMatching(ioServiceSMC)))
+ if service == 0 {
+ return nil, fmt.Errorf("ERROR: %s NOT FOUND", ioServiceSMC)
+ }
+
+ var conn uint32
+ if result := ioServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 {
+ return nil, fmt.Errorf("ERROR: IOServiceOpen failed")
+ }
+
+ ioObjectRelease(service)
+ return &SMC{
+ lib: ioKit,
+ conn: conn,
+ callStruct: ioConnectCallStructMethod,
+ }, nil
+}
+
+func (s *SMC) CallStruct(selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int {
+ return s.callStruct(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt)
+}
+
+func (s *SMC) Close() error {
+ ioServiceClose := GetFunc[IOServiceCloseFunc](s.lib, IOServiceCloseSym)
+
+ if result := ioServiceClose(s.conn); result != 0 {
+ return fmt.Errorf("ERROR: IOServiceClose failed")
+ }
+ return nil
+}
+
+type CStr []byte
+
+func NewCStr(length int32) CStr {
+ return make(CStr, length)
+}
+
+func (s CStr) Length() int32 {
+ // Include null terminator to make CFStringGetCString properly functions
+ return int32(len(s)) + 1
+}
+
+func (s CStr) Ptr() *byte {
+ if len(s) < 1 {
+ return nil
+ }
+
+ return &s[0]
+}
+
+func (c CStr) Addr() uintptr {
+ return uintptr(unsafe.Pointer(c.Ptr()))
+}
+
+func (s CStr) GoString() string {
+ if s == nil {
+ return ""
+ }
+
+ var length int
+ for _, char := range s {
+ if char == '\x00' {
+ break
+ }
+ length++
+ }
+ return string(s[:length])
+}
+
+// https://github.com/ebitengine/purego/blob/main/internal/strings/strings.go#L26
+func GoString(cStr *byte) string {
+ if cStr == nil {
+ return ""
+ }
+ var length int
+ for {
+ if *(*byte)(unsafe.Add(unsafe.Pointer(cStr), uintptr(length))) == '\x00' {
+ break
+ }
+ length++
+ }
+ return string(unsafe.Slice(cStr, length))
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go
new file mode 100644
index 0000000..53cdcee
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || openbsd
+
+package common
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func SysctlUint(mib string) (uint64, error) {
+ buf, err := unix.SysctlRaw(mib)
+ if err != nil {
+ return 0, err
+ }
+ if len(buf) == 8 { // 64 bit
+ return *(*uint64)(unsafe.Pointer(&buf[0])), nil
+ }
+ if len(buf) == 4 { // 32bit
+ t := *(*uint32)(unsafe.Pointer(&buf[0]))
+ return uint64(t), nil
+ }
+ return 0, fmt.Errorf("unexpected size: %s, %d", mib, len(buf))
+}
+
+func DoSysctrl(mib string) ([]string, error) {
+ cmd := exec.Command("sysctl", "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go
new file mode 100644
index 0000000..277034f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package common
+
+import (
+ "context"
+ "errors"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "time"
+)
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+func DoSysctrl(mib string) ([]string, error) {
+ cmd := exec.Command("sysctl", "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func NumProcs() (uint64, error) {
+ return NumProcsWithContext(context.Background())
+}
+
+func NumProcsWithContext(ctx context.Context) (uint64, error) {
+ f, err := os.Open(HostProcWithContext(ctx))
+ if err != nil {
+ return 0, err
+ }
+ defer f.Close()
+
+ list, err := f.Readdirnames(-1)
+ if err != nil {
+ return 0, err
+ }
+ var cnt uint64
+
+ for _, v := range list {
+ if _, err = strconv.ParseUint(v, 10, 64); err == nil {
+ cnt++
+ }
+ }
+
+ return cnt, nil
+}
+
+func BootTimeWithContext(ctx context.Context, enableCache bool) (uint64, error) {
+ if enableCache {
+ t := atomic.LoadUint64(&cachedBootTime)
+ if t != 0 {
+ return t, nil
+ }
+ }
+
+ system, role, err := VirtualizationWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+
+ useStatFile := true
+ if system == "lxc" && role == "guest" {
+ // if lxc, /proc/uptime is used.
+ useStatFile = false
+ } else if system == "docker" && role == "guest" {
+ // also docker, guest
+ useStatFile = false
+ }
+
+ if useStatFile {
+ t, err := readBootTimeStat(ctx)
+ if err != nil {
+ return 0, err
+ }
+ if enableCache {
+ atomic.StoreUint64(&cachedBootTime, t)
+ }
+
+ return t, nil
+ }
+
+ filename := HostProcWithContext(ctx, "uptime")
+ lines, err := ReadLines(filename)
+ if err != nil {
+ return handleBootTimeFileReadErr(err)
+ }
+ currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
+
+ if len(lines) != 1 {
+ return 0, errors.New("wrong uptime format")
+ }
+ f := strings.Fields(lines[0])
+ b, err := strconv.ParseFloat(f[0], 64)
+ if err != nil {
+ return 0, err
+ }
+ t := currentTime - b
+
+ if enableCache {
+ atomic.StoreUint64(&cachedBootTime, uint64(t))
+ }
+
+ return uint64(t), nil
+}
+
+func handleBootTimeFileReadErr(err error) (uint64, error) {
+ if os.IsPermission(err) {
+ var info syscall.Sysinfo_t
+ err := syscall.Sysinfo(&info)
+ if err != nil {
+ return 0, err
+ }
+
+ currentTime := time.Now().UnixNano() / int64(time.Second)
+ t := currentTime - int64(info.Uptime)
+ return uint64(t), nil
+ }
+ return 0, err
+}
+
+func readBootTimeStat(ctx context.Context) (uint64, error) {
+ filename := HostProcWithContext(ctx, "stat")
+ line, err := ReadLine(filename, "btime")
+ if err != nil {
+ return handleBootTimeFileReadErr(err)
+ }
+ if strings.HasPrefix(line, "btime") {
+ f := strings.Fields(line)
+ if len(f) != 2 {
+ return 0, errors.New("wrong btime format")
+ }
+ b, err := strconv.ParseInt(f[1], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ t := uint64(b)
+ return t, nil
+ }
+ return 0, errors.New("could not find btime")
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+// required variables for concurrency safe virtualization caching
+var (
+ cachedVirtMap map[string]string
+ cachedVirtMutex sync.RWMutex
+ cachedVirtOnce sync.Once
+)
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ var system, role string
+
+ // if cached already, return from cache
+ cachedVirtMutex.RLock() // unlock won't be deferred so concurrent reads don't wait for long
+ if cachedVirtMap != nil {
+ cachedSystem, cachedRole := cachedVirtMap["system"], cachedVirtMap["role"]
+ cachedVirtMutex.RUnlock()
+ return cachedSystem, cachedRole, nil
+ }
+ cachedVirtMutex.RUnlock()
+
+ filename := HostProcWithContext(ctx, "xen")
+ if PathExists(filename) {
+ system = "xen"
+ role = "guest" // assume guest
+
+ if PathExists(filepath.Join(filename, "capabilities")) {
+ contents, err := ReadLines(filepath.Join(filename, "capabilities"))
+ if err == nil {
+ if StringsContains(contents, "control_d") {
+ role = "host"
+ }
+ }
+ }
+ }
+
+ filename = HostProcWithContext(ctx, "modules")
+ if PathExists(filename) {
+ contents, err := ReadLines(filename)
+ if err == nil {
+ if StringsContains(contents, "kvm") {
+ system = "kvm"
+ role = "host"
+ } else if StringsContains(contents, "hv_util") {
+ system = "hyperv"
+ role = "guest"
+ } else if StringsContains(contents, "vboxdrv") {
+ system = "vbox"
+ role = "host"
+ } else if StringsContains(contents, "vboxguest") {
+ system = "vbox"
+ role = "guest"
+ } else if StringsContains(contents, "vmware") {
+ system = "vmware"
+ role = "guest"
+ }
+ }
+ }
+
+ filename = HostProcWithContext(ctx, "cpuinfo")
+ if PathExists(filename) {
+ contents, err := ReadLines(filename)
+ if err == nil {
+ if StringsContains(contents, "QEMU Virtual CPU") ||
+ StringsContains(contents, "Common KVM processor") ||
+ StringsContains(contents, "Common 32-bit KVM processor") {
+ system = "kvm"
+ role = "guest"
+ }
+ }
+ }
+
+ filename = HostProcWithContext(ctx, "bus/pci/devices")
+ if PathExists(filename) {
+ contents, err := ReadLines(filename)
+ if err == nil {
+ if StringsContains(contents, "virtio-pci") {
+ role = "guest"
+ }
+ }
+ }
+
+ filename = HostProcWithContext(ctx)
+ if PathExists(filepath.Join(filename, "bc", "0")) {
+ system = "openvz"
+ role = "host"
+ } else if PathExists(filepath.Join(filename, "vz")) {
+ system = "openvz"
+ role = "guest"
+ }
+
+ // not use dmidecode because it requires root
+ if PathExists(filepath.Join(filename, "self", "status")) {
+ contents, err := ReadLines(filepath.Join(filename, "self", "status"))
+ if err == nil {
+ if StringsContains(contents, "s_context:") ||
+ StringsContains(contents, "VxID:") {
+ system = "linux-vserver"
+ }
+ // TODO: guest or host
+ }
+ }
+
+ if PathExists(filepath.Join(filename, "1", "environ")) {
+ contents, err := ReadFile(filepath.Join(filename, "1", "environ"))
+
+ if err == nil {
+ if strings.Contains(contents, "container=lxc") {
+ system = "lxc"
+ role = "guest"
+ }
+ }
+ }
+
+ if PathExists(filepath.Join(filename, "self", "cgroup")) {
+ contents, err := ReadLines(filepath.Join(filename, "self", "cgroup"))
+ if err == nil {
+ if StringsContains(contents, "lxc") {
+ system = "lxc"
+ role = "guest"
+ } else if StringsContains(contents, "docker") {
+ system = "docker"
+ role = "guest"
+ } else if StringsContains(contents, "machine-rkt") {
+ system = "rkt"
+ role = "guest"
+ } else if PathExists("/usr/bin/lxc-version") {
+ system = "lxc"
+ role = "host"
+ }
+ }
+ }
+
+ if PathExists(HostEtcWithContext(ctx, "os-release")) {
+ p, _, err := GetOSReleaseWithContext(ctx)
+ if err == nil && p == "coreos" {
+ system = "rkt" // Is it true?
+ role = "host"
+ }
+ }
+
+ if PathExists(HostRootWithContext(ctx, ".dockerenv")) {
+ system = "docker"
+ role = "guest"
+ }
+
+ // before returning for the first time, cache the system and role
+ cachedVirtOnce.Do(func() {
+ cachedVirtMutex.Lock()
+ defer cachedVirtMutex.Unlock()
+ cachedVirtMap = map[string]string{
+ "system": system,
+ "role": role,
+ }
+ })
+
+ return system, role, nil
+}
+
+func GetOSRelease() (platform string, version string, err error) {
+ return GetOSReleaseWithContext(context.Background())
+}
+
+func GetOSReleaseWithContext(ctx context.Context) (platform string, version string, err error) {
+ contents, err := ReadLines(HostEtcWithContext(ctx, "os-release"))
+ if err != nil {
+ return "", "", nil // return empty
+ }
+ for _, line := range contents {
+ field := strings.Split(line, "=")
+ if len(field) < 2 {
+ continue
+ }
+ switch field[0] {
+ case "ID": // use ID for lowercase
+ platform = trimQuotes(field[1])
+ case "VERSION_ID":
+ version = trimQuotes(field[1])
+ }
+ }
+
+ // cleanup amazon ID
+ if platform == "amzn" {
+ platform = "amazon"
+ }
+
+ return platform, version, nil
+}
+
+// Remove quotes of the source string
+func trimQuotes(s string) string {
+ if len(s) >= 2 {
+ if s[0] == '"' && s[len(s)-1] == '"' {
+ return s[1 : len(s)-1]
+ }
+ }
+ return s
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go
new file mode 100644
index 0000000..2065321
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package common
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrl(mib string) ([]string, error) {
+ cmd := exec.Command("sysctl", "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go
new file mode 100644
index 0000000..00fa19a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package common
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrl(mib string) ([]string, error) {
+ cmd := exec.Command("sysctl", "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go
new file mode 100644
index 0000000..c9f91b1
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux || freebsd || darwin || openbsd
+
+package common
+
+import (
+ "context"
+ "errors"
+ "os/exec"
+ "strconv"
+ "strings"
+)
+
+func CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args ...string) ([]string, error) {
+ var cmd []string
+ if pid == 0 { // will get from all processes.
+ cmd = []string{"-a", "-n", "-P"}
+ } else {
+ cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))}
+ }
+ cmd = append(cmd, args...)
+ out, err := invoke.CommandWithContext(ctx, "lsof", cmd...)
+ if err != nil {
+ if errors.Is(err, exec.ErrNotFound) {
+ return []string{}, err
+ }
+ // if no pid found, lsof returns code 1.
+ if err.Error() == "exit status 1" && len(out) == 0 {
+ return []string{}, nil
+ }
+ }
+ lines := strings.Split(string(out), "\n")
+
+ var ret []string
+ for _, l := range lines[1:] {
+ if len(l) == 0 {
+ continue
+ }
+ ret = append(ret, l)
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go
new file mode 100644
index 0000000..766ed2f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package common
+
+import (
+ "context"
+ "fmt"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "syscall"
+ "unsafe"
+
+ "github.com/yusufpapurcu/wmi"
+ "golang.org/x/sys/windows"
+)
+
+// for double values
+type PDH_FMT_COUNTERVALUE_DOUBLE struct {
+ CStatus uint32
+ DoubleValue float64
+}
+
+// for 64 bit integer values
+type PDH_FMT_COUNTERVALUE_LARGE struct {
+ CStatus uint32
+ LargeValue int64
+}
+
+// for long values
+type PDH_FMT_COUNTERVALUE_LONG struct {
+ CStatus uint32
+ LongValue int32
+ padding [4]byte
+}
+
+// windows system const
+const (
+ ERROR_SUCCESS = 0
+ ERROR_FILE_NOT_FOUND = 2
+ DRIVE_REMOVABLE = 2
+ DRIVE_FIXED = 3
+ HKEY_LOCAL_MACHINE = 0x80000002
+ RRF_RT_REG_SZ = 0x00000002
+ RRF_RT_REG_DWORD = 0x00000010
+ PDH_FMT_LONG = 0x00000100
+ PDH_FMT_DOUBLE = 0x00000200
+ PDH_FMT_LARGE = 0x00000400
+ PDH_INVALID_DATA = 0xc0000bc6
+ PDH_INVALID_HANDLE = 0xC0000bbc
+ PDH_NO_DATA = 0x800007d5
+
+ STATUS_BUFFER_OVERFLOW = 0x80000005
+ STATUS_BUFFER_TOO_SMALL = 0xC0000023
+ STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
+)
+
+const (
+ ProcessBasicInformation = 0
+ ProcessWow64Information = 26
+ ProcessQueryInformation = windows.PROCESS_DUP_HANDLE | windows.PROCESS_QUERY_INFORMATION
+
+ SystemExtendedHandleInformationClass = 64
+)
+
+var (
+ Modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+ ModNt = windows.NewLazySystemDLL("ntdll.dll")
+ ModPdh = windows.NewLazySystemDLL("pdh.dll")
+ ModPsapi = windows.NewLazySystemDLL("psapi.dll")
+
+ ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
+ ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
+ ProcRtlGetNativeSystemInformation = ModNt.NewProc("RtlGetNativeSystemInformation")
+ ProcRtlNtStatusToDosError = ModNt.NewProc("RtlNtStatusToDosError")
+ ProcNtQueryInformationProcess = ModNt.NewProc("NtQueryInformationProcess")
+ ProcNtReadVirtualMemory = ModNt.NewProc("NtReadVirtualMemory")
+ ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64")
+ ProcNtWow64ReadVirtualMemory64 = ModNt.NewProc("NtWow64ReadVirtualMemory64")
+
+ PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
+ PdhAddEnglishCounterW = ModPdh.NewProc("PdhAddEnglishCounterW")
+ PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
+ PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
+ PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
+
+ procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW")
+)
+
+type FILETIME struct {
+ DwLowDateTime uint32
+ DwHighDateTime uint32
+}
+
+// borrowed from net/interface_windows.go
+func BytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+// CounterInfo struct is used to track a windows performance counter
+// copied from https://github.com/mackerelio/mackerel-agent/
+type CounterInfo struct {
+ PostName string
+ CounterName string
+ Counter windows.Handle
+}
+
+// CreateQuery with a PdhOpenQuery call
+// copied from https://github.com/mackerelio/mackerel-agent/
+func CreateQuery() (windows.Handle, error) {
+ var query windows.Handle
+ r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
+ if r != 0 {
+ return 0, err
+ }
+ return query, nil
+}
+
+// CreateCounter with a PdhAddEnglishCounterW call
+func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
+ var counter windows.Handle
+ r, _, err := PdhAddEnglishCounterW.Call(
+ uintptr(query),
+ uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))),
+ 0,
+ uintptr(unsafe.Pointer(&counter)))
+ if r != 0 {
+ return nil, err
+ }
+ return &CounterInfo{
+ PostName: pname,
+ CounterName: cname,
+ Counter: counter,
+ }, nil
+}
+
+// GetCounterValue get counter value from handle
+// adapted from https://github.com/mackerelio/mackerel-agent/
+func GetCounterValue(counter windows.Handle) (float64, error) {
+ var value PDH_FMT_COUNTERVALUE_DOUBLE
+ r, _, err := PdhGetFormattedCounterValue.Call(uintptr(counter), PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&value)))
+ if r != 0 && r != PDH_INVALID_DATA {
+ return 0.0, err
+ }
+ return value.DoubleValue, nil
+}
+
+type Win32PerformanceCounter struct {
+ PostName string
+ CounterName string
+ Query windows.Handle
+ Counter windows.Handle
+}
+
+func NewWin32PerformanceCounter(postName, counterName string) (*Win32PerformanceCounter, error) {
+ query, err := CreateQuery()
+ if err != nil {
+ return nil, err
+ }
+ counter := Win32PerformanceCounter{
+ Query: query,
+ PostName: postName,
+ CounterName: counterName,
+ }
+ r, _, err := PdhAddEnglishCounterW.Call(
+ uintptr(counter.Query),
+ uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))),
+ 0,
+ uintptr(unsafe.Pointer(&counter.Counter)),
+ )
+ if r != 0 {
+ return nil, err
+ }
+ return &counter, nil
+}
+
+func (w *Win32PerformanceCounter) GetValue() (float64, error) {
+ r, _, err := PdhCollectQueryData.Call(uintptr(w.Query))
+ if r != 0 && err != nil {
+ if r == PDH_NO_DATA {
+ return 0.0, fmt.Errorf("%w: this counter has not data", err)
+ }
+ return 0.0, err
+ }
+
+ return GetCounterValue(w.Counter)
+}
+
+func ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) {
+ return NewWin32PerformanceCounter("processor_queue_length", `\System\Processor Queue Length`)
+}
+
+// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
+func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
+ if _, ok := ctx.Deadline(); !ok {
+ ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
+ defer cancel()
+ ctx = ctxTimeout
+ }
+
+ errChan := make(chan error, 1)
+ go func() {
+ errChan <- wmi.Query(query, dst, connectServerArgs...)
+ }()
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case err := <-errChan:
+ return err
+ }
+}
+
+// Convert paths using native DOS format like:
+//
+// "\Device\HarddiskVolume1\Windows\systemew\file.txt"
+//
+// into:
+//
+// "C:\Windows\systemew\file.txt"
+func ConvertDOSPath(p string) string {
+ rawDrive := strings.Join(strings.Split(p, `\`)[:3], `\`)
+
+ for d := 'A'; d <= 'Z'; d++ {
+ szDeviceName := string(d) + ":"
+ szTarget := make([]uint16, 512)
+ ret, _, _ := procQueryDosDeviceW.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(szDeviceName))),
+ uintptr(unsafe.Pointer(&szTarget[0])),
+ uintptr(len(szTarget)))
+ if ret != 0 && windows.UTF16ToString(szTarget[:]) == rawDrive {
+ return filepath.Join(szDeviceName, p[len(rawDrive):])
+ }
+ }
+ return p
+}
+
+type NtStatus uint32
+
+func (s NtStatus) Error() error {
+ if s == 0 {
+ return nil
+ }
+ return fmt.Errorf("NtStatus 0x%08x", uint32(s))
+}
+
+func (s NtStatus) IsError() bool {
+ return s>>30 == 3
+}
+
+type SystemExtendedHandleTableEntryInformation struct {
+ Object uintptr
+ UniqueProcessId uintptr
+ HandleValue uintptr
+ GrantedAccess uint32
+ CreatorBackTraceIndex uint16
+ ObjectTypeIndex uint16
+ HandleAttributes uint32
+ Reserved uint32
+}
+
+type SystemExtendedHandleInformation struct {
+ NumberOfHandles uintptr
+ Reserved uintptr
+ Handles [1]SystemExtendedHandleTableEntryInformation
+}
+
+// CallWithExpandingBuffer https://github.com/hillu/go-ntdll
+func CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus {
+ for {
+ if st := fn(); st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH {
+ if int(*resultLength) <= cap(*buf) {
+ (*reflect.SliceHeader)(unsafe.Pointer(buf)).Len = int(*resultLength)
+ } else {
+ *buf = make([]byte, int(*resultLength))
+ }
+ continue
+ } else {
+ if !st.IsError() {
+ *buf = (*buf)[:int(*resultLength)]
+ }
+ return st
+ }
+ }
+}
+
+func NtQuerySystemInformation(
+ SystemInformationClass uint32,
+ SystemInformation *byte,
+ SystemInformationLength uint32,
+ ReturnLength *uint32,
+) NtStatus {
+ r0, _, _ := ProcNtQuerySystemInformation.Call(
+ uintptr(SystemInformationClass),
+ uintptr(unsafe.Pointer(SystemInformation)),
+ uintptr(SystemInformationLength),
+ uintptr(unsafe.Pointer(ReturnLength)))
+ return NtStatus(r0)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go
new file mode 100644
index 0000000..113ff2e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import "unsafe"
+
+// IsLittleEndian checks if the current platform uses little-endian.
+// copied from https://github.com/ntrrg/ntgo/blob/v0.8.0/runtime/infrastructure.go#L16 (MIT License)
+func IsLittleEndian() bool {
+ var x int16 = 0x0011
+ return *(*byte)(unsafe.Pointer(&x)) == 0x11
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go
new file mode 100644
index 0000000..504f13f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import (
+ "context"
+ "time"
+)
+
+// Sleep awaits for provided interval.
+// Can be interrupted by context cancellation.
+func Sleep(ctx context.Context, interval time.Duration) error {
+ timer := time.NewTimer(interval)
+ select {
+ case <-ctx.Done():
+ if !timer.Stop() {
+ <-timer.C
+ }
+ return ctx.Err()
+ case <-timer.C:
+ return nil
+ }
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go
new file mode 100644
index 0000000..888cc57
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import "fmt"
+
+type Warnings struct {
+ List []error
+ Verbose bool
+}
+
+func (w *Warnings) Add(err error) {
+ w.List = append(w.List, err)
+}
+
+func (w *Warnings) Reference() error {
+ if len(w.List) > 0 {
+ return w
+ }
+ return nil
+}
+
+func (w *Warnings) Error() string {
+ if w.Verbose {
+ str := ""
+ for i, e := range w.List {
+ str += fmt.Sprintf("\tError %d: %s\n", i, e.Error())
+ }
+ return str
+ }
+ return fmt.Sprintf("Number of warnings: %v", len(w.List))
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go
new file mode 100644
index 0000000..0a12fe2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package mem
+
+import (
+ "context"
+ "encoding/json"
+)
+
+type ExVirtualMemory struct {
+ ActiveFile uint64 `json:"activefile"`
+ InactiveFile uint64 `json:"inactivefile"`
+ ActiveAnon uint64 `json:"activeanon"`
+ InactiveAnon uint64 `json:"inactiveanon"`
+ Unevictable uint64 `json:"unevictable"`
+}
+
+func (v ExVirtualMemory) String() string {
+ s, _ := json.Marshal(v)
+ return string(s)
+}
+
+type ExLinux struct{}
+
+func NewExLinux() *ExLinux {
+ return &ExLinux{}
+}
+
+func (ex *ExLinux) VirtualMemory() (*ExVirtualMemory, error) {
+ return ex.VirtualMemoryWithContext(context.Background())
+}
+
+func (ex *ExLinux) VirtualMemoryWithContext(ctx context.Context) (*ExVirtualMemory, error) {
+ _, vmEx, err := fillFromMeminfoWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return vmEx, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go b/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go
new file mode 100644
index 0000000..5c49a47
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package mem
+
+import (
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// ExVirtualMemory represents Windows specific information
+// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
+// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information
+type ExVirtualMemory struct {
+ CommitLimit uint64 `json:"commitLimit"`
+ CommitTotal uint64 `json:"commitTotal"`
+ VirtualTotal uint64 `json:"virtualTotal"`
+ VirtualAvail uint64 `json:"virtualAvail"`
+}
+
+type ExWindows struct{}
+
+func NewExWindows() *ExWindows {
+ return &ExWindows{}
+}
+
+func (e *ExWindows) VirtualMemory() (*ExVirtualMemory, error) {
+ var memInfo memoryStatusEx
+ memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
+ mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
+ if mem == 0 {
+ return nil, windows.GetLastError()
+ }
+
+ var perfInfo performanceInformation
+ perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
+ perf, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
+ if perf == 0 {
+ return nil, windows.GetLastError()
+ }
+
+ ret := &ExVirtualMemory{
+ CommitLimit: perfInfo.commitLimit * perfInfo.pageSize,
+ CommitTotal: perfInfo.commitTotal * perfInfo.pageSize,
+ VirtualTotal: memInfo.ullTotalVirtual,
+ VirtualAvail: memInfo.ullAvailVirtual,
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go
new file mode 100644
index 0000000..0da71a9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package mem
+
+import (
+ "encoding/json"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+// Memory usage statistics. Total, Available and Used contain numbers of bytes
+// for human consumption.
+//
+// The other fields in this struct contain kernel specific values.
+type VirtualMemoryStat struct {
+ // Total amount of RAM on this system
+ Total uint64 `json:"total"`
+
+ // RAM available for programs to allocate
+ //
+ // This value is computed from the kernel specific values.
+ Available uint64 `json:"available"`
+
+ // RAM used by programs
+ //
+ // This value is computed from the kernel specific values.
+ Used uint64 `json:"used"`
+
+ // Percentage of RAM used by programs
+ //
+ // This value is computed from the kernel specific values.
+ UsedPercent float64 `json:"usedPercent"`
+
+ // This is the kernel's notion of free memory; RAM chips whose bits nobody
+ // cares about the value of right now. For a human consumable number,
+ // Available is what you really want.
+ Free uint64 `json:"free"`
+
+ // OS X / BSD specific numbers:
+ // http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
+ Active uint64 `json:"active"`
+ Inactive uint64 `json:"inactive"`
+ Wired uint64 `json:"wired"`
+
+ // FreeBSD specific numbers:
+ // https://reviews.freebsd.org/D8467
+ Laundry uint64 `json:"laundry"`
+
+ // Linux specific numbers
+ // https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+ // https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
+ // https://www.kernel.org/doc/Documentation/vm/transhuge.txt
+ Buffers uint64 `json:"buffers"`
+ Cached uint64 `json:"cached"`
+ WriteBack uint64 `json:"writeBack"`
+ Dirty uint64 `json:"dirty"`
+ WriteBackTmp uint64 `json:"writeBackTmp"`
+ Shared uint64 `json:"shared"`
+ Slab uint64 `json:"slab"`
+ Sreclaimable uint64 `json:"sreclaimable"`
+ Sunreclaim uint64 `json:"sunreclaim"`
+ PageTables uint64 `json:"pageTables"`
+ SwapCached uint64 `json:"swapCached"`
+ CommitLimit uint64 `json:"commitLimit"`
+ CommittedAS uint64 `json:"committedAS"`
+ HighTotal uint64 `json:"highTotal"`
+ HighFree uint64 `json:"highFree"`
+ LowTotal uint64 `json:"lowTotal"`
+ LowFree uint64 `json:"lowFree"`
+ SwapTotal uint64 `json:"swapTotal"`
+ SwapFree uint64 `json:"swapFree"`
+ Mapped uint64 `json:"mapped"`
+ VmallocTotal uint64 `json:"vmallocTotal"`
+ VmallocUsed uint64 `json:"vmallocUsed"`
+ VmallocChunk uint64 `json:"vmallocChunk"`
+ HugePagesTotal uint64 `json:"hugePagesTotal"`
+ HugePagesFree uint64 `json:"hugePagesFree"`
+ HugePagesRsvd uint64 `json:"hugePagesRsvd"`
+ HugePagesSurp uint64 `json:"hugePagesSurp"`
+ HugePageSize uint64 `json:"hugePageSize"`
+ AnonHugePages uint64 `json:"anonHugePages"`
+}
+
+type SwapMemoryStat struct {
+ Total uint64 `json:"total"`
+ Used uint64 `json:"used"`
+ Free uint64 `json:"free"`
+ UsedPercent float64 `json:"usedPercent"`
+ Sin uint64 `json:"sin"`
+ Sout uint64 `json:"sout"`
+ PgIn uint64 `json:"pgIn"`
+ PgOut uint64 `json:"pgOut"`
+ PgFault uint64 `json:"pgFault"`
+
+ // Linux specific numbers
+ // https://www.kernel.org/doc/Documentation/cgroup-v2.txt
+ PgMajFault uint64 `json:"pgMajFault"`
+}
+
+func (m VirtualMemoryStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+func (m SwapMemoryStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+type SwapDevice struct {
+ Name string `json:"name"`
+ UsedBytes uint64 `json:"usedBytes"`
+ FreeBytes uint64 `json:"freeBytes"`
+}
+
+func (m SwapDevice) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go
new file mode 100644
index 0000000..ac2c39d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package mem
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go
new file mode 100644
index 0000000..2d03dd0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package mem
+
+import (
+ "context"
+
+ "github.com/power-devops/perfstat"
+)
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ m, err := perfstat.MemoryTotalStat()
+ if err != nil {
+ return nil, err
+ }
+ pagesize := uint64(4096)
+ ret := VirtualMemoryStat{
+ Total: uint64(m.RealTotal) * pagesize,
+ Available: uint64(m.RealAvailable) * pagesize,
+ Free: uint64(m.RealFree) * pagesize,
+ Used: uint64(m.RealInUse) * pagesize,
+ UsedPercent: 100 * float64(m.RealInUse) / float64(m.RealTotal),
+ Active: uint64(m.VirtualActive) * pagesize,
+ SwapTotal: uint64(m.PgSpTotal) * pagesize,
+ SwapFree: uint64(m.PgSpFree) * pagesize,
+ }
+ return &ret, nil
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ m, err := perfstat.MemoryTotalStat()
+ if err != nil {
+ return nil, err
+ }
+ pagesize := uint64(4096)
+ swapUsed := uint64(m.PgSpTotal-m.PgSpFree-m.PgSpRsvd) * pagesize
+ swapTotal := uint64(m.PgSpTotal) * pagesize
+ ret := SwapMemoryStat{
+ Total: swapTotal,
+ Free: uint64(m.PgSpFree) * pagesize,
+ Used: swapUsed,
+ UsedPercent: float64(100*swapUsed) / float64(swapTotal),
+ Sin: uint64(m.PgSpIn),
+ Sout: uint64(m.PgSpOut),
+ PgIn: uint64(m.PageIn),
+ PgOut: uint64(m.PageOut),
+ PgFault: uint64(m.PageFaults),
+ }
+ return &ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go
new file mode 100644
index 0000000..bc3c0ed
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package mem
+
+import (
+ "context"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ vmem, swap, err := callSVMon(ctx, true)
+ if err != nil {
+ return nil, err
+ }
+ if vmem.Total == 0 {
+ return nil, common.ErrNotImplementedError
+ }
+ vmem.SwapTotal = swap.Total
+ vmem.SwapFree = swap.Free
+ return vmem, nil
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ _, swap, err := callSVMon(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+ if swap.Total == 0 {
+ return nil, common.ErrNotImplementedError
+ }
+ return swap, nil
+}
+
+func callSVMon(ctx context.Context, virt bool) (*VirtualMemoryStat, *SwapMemoryStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "svmon", "-G")
+ if err != nil {
+ return nil, nil, err
+ }
+
+ pagesize := uint64(4096)
+ vmem := &VirtualMemoryStat{}
+ swap := &SwapMemoryStat{}
+ for _, line := range strings.Split(string(out), "\n") {
+ if virt && strings.HasPrefix(line, "memory") {
+ p := strings.Fields(line)
+ if len(p) > 2 {
+ if t, err := strconv.ParseUint(p[1], 10, 64); err == nil {
+ vmem.Total = t * pagesize
+ }
+ if t, err := strconv.ParseUint(p[2], 10, 64); err == nil {
+ vmem.Used = t * pagesize
+ if vmem.Total > 0 {
+ vmem.UsedPercent = 100 * float64(vmem.Used) / float64(vmem.Total)
+ }
+ }
+ if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+ vmem.Free = t * pagesize
+ }
+ }
+ } else if strings.HasPrefix(line, "pg space") {
+ p := strings.Fields(line)
+ if len(p) > 3 {
+ if t, err := strconv.ParseUint(p[2], 10, 64); err == nil {
+ swap.Total = t * pagesize
+ }
+ if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+ swap.Free = swap.Total - t*pagesize
+ }
+ }
+ break
+ }
+ }
+ return vmem, swap, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go
new file mode 100644
index 0000000..4f3e57c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || openbsd || netbsd
+
+package mem
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const swapCommand = "swapctl"
+
+// swapctl column indexes
+const (
+ nameCol = 0
+ totalKiBCol = 1
+ usedKiBCol = 2
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ output, err := invoke.CommandWithContext(ctx, swapCommand, "-lk")
+ if err != nil {
+ return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
+ }
+
+ return parseSwapctlOutput(string(output))
+}
+
+func parseSwapctlOutput(output string) ([]*SwapDevice, error) {
+ lines := strings.Split(output, "\n")
+ if len(lines) == 0 {
+ return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
+ }
+
+ // Check header headerFields are as expected.
+ header := lines[0]
+ header = strings.ToLower(header)
+ header = strings.ReplaceAll(header, ":", "")
+ headerFields := strings.Fields(header)
+ if len(headerFields) < usedKiBCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, header)
+ }
+ if headerFields[nameCol] != "device" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "device")
+ }
+ if headerFields[totalKiBCol] != "1kb-blocks" && headerFields[totalKiBCol] != "1k-blocks" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalKiBCol], "1kb-blocks")
+ }
+ if headerFields[usedKiBCol] != "used" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[usedKiBCol], "used")
+ }
+
+ var swapDevices []*SwapDevice
+ for _, line := range lines[1:] {
+ if line == "" {
+ continue // the terminal line is typically empty
+ }
+ fields := strings.Fields(line)
+ if len(fields) < usedKiBCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
+ }
+
+ totalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
+ }
+
+ usedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
+ }
+
+ swapDevices = append(swapDevices, &SwapDevice{
+ Name: fields[nameCol],
+ UsedBytes: usedKiB * 1024,
+ FreeBytes: (totalKiB - usedKiB) * 1024,
+ })
+ }
+
+ return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go
new file mode 100644
index 0000000..a4c15f6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package mem
+
+import (
+ "context"
+ "fmt"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func getHwMemsize() (uint64, error) {
+ total, err := unix.SysctlUint64("hw.memsize")
+ if err != nil {
+ return 0, err
+ }
+ return total, nil
+}
+
+// xsw_usage in sys/sysctl.h
+type swapUsage struct {
+ Total uint64
+ Avail uint64
+ Used uint64
+ Pagesize int32
+ Encrypted bool
+}
+
+// SwapMemory returns swapinfo.
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ // https://github.com/yanllearnn/go-osstat/blob/ae8a279d26f52ec946a03698c7f50a26cfb427e3/memory/memory_darwin.go
+ var ret *SwapMemoryStat
+
+ value, err := unix.SysctlRaw("vm.swapusage")
+ if err != nil {
+ return ret, err
+ }
+ if len(value) != 32 {
+ return ret, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value))
+ }
+ swap := (*swapUsage)(unsafe.Pointer(&value[0]))
+
+ u := float64(0)
+ if swap.Total != 0 {
+ u = ((float64(swap.Total) - float64(swap.Avail)) / float64(swap.Total)) * 100.0
+ }
+
+ ret = &SwapMemoryStat{
+ Total: swap.Total,
+ Used: swap.Used,
+ Free: swap.Avail,
+ UsedPercent: u,
+ }
+
+ return ret, nil
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+type vmStatisticsData struct {
+ freeCount uint32
+ activeCount uint32
+ inactiveCount uint32
+ wireCount uint32
+ _ [44]byte // Not used here
+}
+
+// VirtualMemory returns VirtualmemoryStat.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ machLib, err := common.NewLibrary(common.System)
+ if err != nil {
+ return nil, err
+ }
+ defer machLib.Close()
+
+ hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym)
+ machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym)
+
+ count := uint32(common.HOST_VM_INFO_COUNT)
+ var vmstat vmStatisticsData
+
+ status := hostStatistics(machHostSelf(), common.HOST_VM_INFO,
+ uintptr(unsafe.Pointer(&vmstat)), &count)
+
+ if status != common.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_statistics error=%d", status)
+ }
+
+ pageSizeAddr, _ := machLib.Dlsym("vm_kernel_page_size")
+ pageSize := **(**uint64)(unsafe.Pointer(&pageSizeAddr))
+ total, err := getHwMemsize()
+ if err != nil {
+ return nil, err
+ }
+ totalCount := uint32(total / pageSize)
+
+ availableCount := vmstat.inactiveCount + vmstat.freeCount
+ usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
+
+ usedCount := totalCount - availableCount
+
+ return &VirtualMemoryStat{
+ Total: total,
+ Available: pageSize * uint64(availableCount),
+ Used: pageSize * uint64(usedCount),
+ UsedPercent: usedPercent,
+ Free: pageSize * uint64(vmstat.freeCount),
+ Active: pageSize * uint64(vmstat.activeCount),
+ Inactive: pageSize * uint64(vmstat.inactiveCount),
+ Wired: pageSize * uint64(vmstat.wireCount),
+ }, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go
new file mode 100644
index 0000000..ba882c8
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix && !netbsd
+
+package mem
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go
new file mode 100644
index 0000000..a6dedde
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package mem
+
+import (
+ "context"
+ "errors"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ physmem, err := common.SysctlUint("hw.physmem")
+ if err != nil {
+ return nil, err
+ }
+
+ free, err := common.SysctlUint("vm.stats.vm.v_free_count")
+ if err != nil {
+ return nil, err
+ }
+ active, err := common.SysctlUint("vm.stats.vm.v_active_count")
+ if err != nil {
+ return nil, err
+ }
+ inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count")
+ if err != nil {
+ return nil, err
+ }
+ buffers, err := common.SysctlUint("vfs.bufspace")
+ if err != nil {
+ return nil, err
+ }
+ wired, err := common.SysctlUint("vm.stats.vm.v_wire_count")
+ if err != nil {
+ return nil, err
+ }
+ var cached, laundry uint64
+ osreldate, _ := common.SysctlUint("kern.osreldate")
+ if osreldate < 1102000 {
+ cached, err = common.SysctlUint("vm.stats.vm.v_cache_count")
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count")
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ p := pageSize
+ ret := &VirtualMemoryStat{
+ Total: physmem,
+ Free: free * p,
+ Active: active * p,
+ Inactive: inactive * p,
+ Cached: cached * p,
+ Buffers: buffers,
+ Wired: wired * p,
+ Laundry: laundry * p,
+ }
+
+ ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ return ret, nil
+}
+
+// Return swapinfo
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+// Constants from vm/vm_param.h
+const (
+ XSWDEV_VERSION11 = 1
+ XSWDEV_VERSION = 2
+)
+
+// Types from vm/vm_param.h
+type xswdev struct {
+ Version uint32 // Version is the version
+ Dev uint64 // Dev is the device identifier
+ Flags int32 // Flags is the swap flags applied to the device
+ NBlks int32 // NBlks is the total number of blocks
+ Used int32 // Used is the number of blocks used
+}
+
+// xswdev11 is a compatibility for under FreeBSD 11
+// sys/vm/swap_pager.c
+type xswdev11 struct {
+ Version uint32 // Version is the version
+ Dev uint32 // Dev is the device identifier
+ Flags int32 // Flags is the swap flags applied to the device
+ NBlks int32 // NBlks is the total number of blocks
+ Used int32 // Used is the number of blocks used
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ // FreeBSD can have multiple swap devices so we total them up
+ i, err := common.SysctlUint("vm.nswapdev")
+ if err != nil {
+ return nil, err
+ }
+
+ if i == 0 {
+ return nil, errors.New("no swap devices found")
+ }
+
+ c := int(i)
+
+ i, err = common.SysctlUint("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ pageSize := i
+
+ var buf []byte
+ s := &SwapMemoryStat{}
+ for n := 0; n < c; n++ {
+ buf, err = unix.SysctlRaw("vm.swap_info", n)
+ if err != nil {
+ return nil, err
+ }
+
+ // first, try to parse with version 2
+ xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
+ if xsw.Version == XSWDEV_VERSION11 {
+ // this is version 1, so try to parse again
+ xsw := (*xswdev11)(unsafe.Pointer(&buf[0]))
+ if xsw.Version != XSWDEV_VERSION11 {
+ return nil, errors.New("xswdev version mismatch(11)")
+ }
+ s.Total += uint64(xsw.NBlks)
+ s.Used += uint64(xsw.Used)
+ } else if xsw.Version != XSWDEV_VERSION {
+ return nil, errors.New("xswdev version mismatch")
+ } else {
+ s.Total += uint64(xsw.NBlks)
+ s.Used += uint64(xsw.Used)
+ }
+
+ }
+
+ if s.Total != 0 {
+ s.UsedPercent = float64(s.Used) / float64(s.Total) * 100
+ }
+ s.Total *= pageSize
+ s.Used *= pageSize
+ s.Free = s.Total - s.Used
+
+ return s, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go
new file mode 100644
index 0000000..05bfdaf
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package mem
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "io"
+ "math"
+ "os"
+ "strconv"
+ "strings"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ vm, _, err := fillFromMeminfoWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return vm, nil
+}
+
+func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *ExVirtualMemory, error) {
+ filename := common.HostProcWithContext(ctx, "meminfo")
+ lines, _ := common.ReadLines(filename)
+
+ // flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
+ memavail := false
+ activeFile := false // "Active(file)" not available: 2.6.28 / Dec 2008
+ inactiveFile := false // "Inactive(file)" not available: 2.6.28 / Dec 2008
+ sReclaimable := false // "Sreclaimable:" not available: 2.6.19 / Nov 2006
+
+ ret := &VirtualMemoryStat{}
+ retEx := &ExVirtualMemory{}
+
+ for _, line := range lines {
+ fields := strings.Split(line, ":")
+ if len(fields) != 2 {
+ continue
+ }
+ key := strings.TrimSpace(fields[0])
+ value := strings.TrimSpace(fields[1])
+ value = strings.Replace(value, " kB", "", -1)
+
+ switch key {
+ case "MemTotal":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Total = t * 1024
+ case "MemFree":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Free = t * 1024
+ case "MemAvailable":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ memavail = true
+ ret.Available = t * 1024
+ case "Buffers":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Buffers = t * 1024
+ case "Cached":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Cached = t * 1024
+ case "Active":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Active = t * 1024
+ case "Inactive":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Inactive = t * 1024
+ case "Active(anon)":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ retEx.ActiveAnon = t * 1024
+ case "Inactive(anon)":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ retEx.InactiveAnon = t * 1024
+ case "Active(file)":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ activeFile = true
+ retEx.ActiveFile = t * 1024
+ case "Inactive(file)":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ inactiveFile = true
+ retEx.InactiveFile = t * 1024
+ case "Unevictable":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ retEx.Unevictable = t * 1024
+ case "Writeback":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.WriteBack = t * 1024
+ case "WritebackTmp":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.WriteBackTmp = t * 1024
+ case "Dirty":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Dirty = t * 1024
+ case "Shmem":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Shared = t * 1024
+ case "Slab":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Slab = t * 1024
+ case "SReclaimable":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ sReclaimable = true
+ ret.Sreclaimable = t * 1024
+ case "SUnreclaim":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Sunreclaim = t * 1024
+ case "PageTables":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.PageTables = t * 1024
+ case "SwapCached":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.SwapCached = t * 1024
+ case "CommitLimit":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.CommitLimit = t * 1024
+ case "Committed_AS":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.CommittedAS = t * 1024
+ case "HighTotal":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HighTotal = t * 1024
+ case "HighFree":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HighFree = t * 1024
+ case "LowTotal":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.LowTotal = t * 1024
+ case "LowFree":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.LowFree = t * 1024
+ case "SwapTotal":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.SwapTotal = t * 1024
+ case "SwapFree":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.SwapFree = t * 1024
+ case "Mapped":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.Mapped = t * 1024
+ case "VmallocTotal":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.VmallocTotal = t * 1024
+ case "VmallocUsed":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.VmallocUsed = t * 1024
+ case "VmallocChunk":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.VmallocChunk = t * 1024
+ case "HugePages_Total":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HugePagesTotal = t
+ case "HugePages_Free":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HugePagesFree = t
+ case "HugePages_Rsvd":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HugePagesRsvd = t
+ case "HugePages_Surp":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HugePagesSurp = t
+ case "Hugepagesize":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.HugePageSize = t * 1024
+ case "AnonHugePages":
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, retEx, err
+ }
+ ret.AnonHugePages = t * 1024
+ }
+ }
+
+ ret.Cached += ret.Sreclaimable
+
+ if !memavail {
+ if activeFile && inactiveFile && sReclaimable {
+ ret.Available = calculateAvailVmem(ctx, ret, retEx)
+ } else {
+ ret.Available = ret.Cached + ret.Free
+ }
+ }
+
+ ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ return ret, retEx, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ sysinfo := &unix.Sysinfo_t{}
+
+ if err := unix.Sysinfo(sysinfo); err != nil {
+ return nil, err
+ }
+ ret := &SwapMemoryStat{
+ Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),
+ Free: uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),
+ }
+ ret.Used = ret.Total - ret.Free
+ // check Infinity
+ if ret.Total != 0 {
+ ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
+ } else {
+ ret.UsedPercent = 0
+ }
+ filename := common.HostProcWithContext(ctx, "vmstat")
+ lines, _ := common.ReadLines(filename)
+ for _, l := range lines {
+ fields := strings.Fields(l)
+ if len(fields) < 2 {
+ continue
+ }
+ switch fields[0] {
+ case "pswpin":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.Sin = value * 4 * 1024
+ case "pswpout":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.Sout = value * 4 * 1024
+ case "pgpgin":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.PgIn = value * 4 * 1024
+ case "pgpgout":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.PgOut = value * 4 * 1024
+ case "pgfault":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.PgFault = value * 4 * 1024
+ case "pgmajfault":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.PgMajFault = value * 4 * 1024
+ }
+ }
+ return ret, nil
+}
+
+// calculateAvailVmem is a fallback under kernel 3.14 where /proc/meminfo does not provide
+// "MemAvailable:" column. It reimplements an algorithm from the link below
+// https://github.com/giampaolo/psutil/pull/890
+func calculateAvailVmem(ctx context.Context, ret *VirtualMemoryStat, retEx *ExVirtualMemory) uint64 {
+ var watermarkLow uint64
+
+ fn := common.HostProcWithContext(ctx, "zoneinfo")
+ lines, err := common.ReadLines(fn)
+ if err != nil {
+ return ret.Free + ret.Cached // fallback under kernel 2.6.13
+ }
+
+ pagesize := uint64(os.Getpagesize())
+ watermarkLow = 0
+
+ for _, line := range lines {
+ fields := strings.Fields(line)
+
+ if strings.HasPrefix(fields[0], "low") {
+ lowValue, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ lowValue = 0
+ }
+ watermarkLow += lowValue
+ }
+ }
+
+ watermarkLow *= pagesize
+
+ availMemory := ret.Free - watermarkLow
+ pageCache := retEx.ActiveFile + retEx.InactiveFile
+ pageCache -= uint64(math.Min(float64(pageCache/2), float64(watermarkLow)))
+ availMemory += pageCache
+ availMemory += ret.Sreclaimable - uint64(math.Min(float64(ret.Sreclaimable/2.0), float64(watermarkLow)))
+
+ if availMemory < 0 {
+ availMemory = 0
+ }
+
+ return availMemory
+}
+
+const swapsFilename = "swaps"
+
+// swaps file column indexes
+const (
+ nameCol = 0
+ // typeCol = 1
+ totalCol = 2
+ usedCol = 3
+ // priorityCol = 4
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ swapsFilePath := common.HostProcWithContext(ctx, swapsFilename)
+ f, err := os.Open(swapsFilePath)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseSwapsFile(ctx, f)
+}
+
+func parseSwapsFile(ctx context.Context, r io.Reader) ([]*SwapDevice, error) {
+ swapsFilePath := common.HostProcWithContext(ctx, swapsFilename)
+ scanner := bufio.NewScanner(r)
+ if !scanner.Scan() {
+ if err := scanner.Err(); err != nil {
+ return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err)
+ }
+ return nil, fmt.Errorf("unexpected end-of-file in %q", swapsFilePath)
+
+ }
+
+ // Check header headerFields are as expected
+ headerFields := strings.Fields(scanner.Text())
+ if len(headerFields) < usedCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields in header", swapsFilePath)
+ }
+ if headerFields[nameCol] != "Filename" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[nameCol], "Filename")
+ }
+ if headerFields[totalCol] != "Size" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[totalCol], "Size")
+ }
+ if headerFields[usedCol] != "Used" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[usedCol], "Used")
+ }
+
+ var swapDevices []*SwapDevice
+ for scanner.Scan() {
+ fields := strings.Fields(scanner.Text())
+ if len(fields) < usedCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields", swapsFilePath)
+ }
+
+ totalKiB, err := strconv.ParseUint(fields[totalCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapsFilePath, err)
+ }
+
+ usedKiB, err := strconv.ParseUint(fields[usedCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapsFilePath, err)
+ }
+
+ swapDevices = append(swapDevices, &SwapDevice{
+ Name: fields[nameCol],
+ UsedBytes: usedKiB * 1024,
+ FreeBytes: (totalKiB - usedKiB) * 1024,
+ })
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err)
+ }
+
+ return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go
new file mode 100644
index 0000000..0a41b3e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package mem
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "golang.org/x/sys/unix"
+)
+
+func GetPageSize() (uint64, error) {
+ return GetPageSizeWithContext(context.Background())
+}
+
+func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
+ uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
+ if err != nil {
+ return 0, err
+ }
+ return uint64(uvmexp.Pagesize), nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
+ if err != nil {
+ return nil, err
+ }
+ p := uint64(uvmexp.Pagesize)
+
+ ret := &VirtualMemoryStat{
+ Total: uint64(uvmexp.Npages) * p,
+ Free: uint64(uvmexp.Free) * p,
+ Active: uint64(uvmexp.Active) * p,
+ Inactive: uint64(uvmexp.Inactive) * p,
+ Cached: 0, // not available
+ Wired: uint64(uvmexp.Wired) * p,
+ }
+
+ ret.Available = ret.Inactive + ret.Cached + ret.Free
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ // Get buffers from vm.bufmem sysctl
+ ret.Buffers, err = unix.SysctlUint64("vm.bufmem")
+ if err != nil {
+ return nil, err
+ }
+
+ return ret, nil
+}
+
+// Return swapctl summary info
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "swapctl", "-sk")
+ if err != nil {
+ return &SwapMemoryStat{}, nil
+ }
+
+ line := string(out)
+ var total, used, free uint64
+
+ _, err = fmt.Sscanf(line,
+ "total: %d 1K-blocks allocated, %d used, %d available",
+ &total, &used, &free)
+ if err != nil {
+ return nil, errors.New("failed to parse swapctl output")
+ }
+
+ percent := float64(used) / float64(total) * 100
+ return &SwapMemoryStat{
+ Total: total * 1024,
+ Used: used * 1024,
+ Free: free * 1024,
+ UsedPercent: percent,
+ }, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go
new file mode 100644
index 0000000..2510bb0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package mem
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "errors"
+ "fmt"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "golang.org/x/sys/unix"
+)
+
+func GetPageSize() (uint64, error) {
+ return GetPageSizeWithContext(context.Background())
+}
+
+func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
+ uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
+ if err != nil {
+ return 0, err
+ }
+ return uint64(uvmexp.Pagesize), nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
+ if err != nil {
+ return nil, err
+ }
+ p := uint64(uvmexp.Pagesize)
+
+ ret := &VirtualMemoryStat{
+ Total: uint64(uvmexp.Npages) * p,
+ Free: uint64(uvmexp.Free) * p,
+ Active: uint64(uvmexp.Active) * p,
+ Inactive: uint64(uvmexp.Inactive) * p,
+ Cached: 0, // not available
+ Wired: uint64(uvmexp.Wired) * p,
+ }
+
+ ret.Available = ret.Inactive + ret.Cached + ret.Free
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ mib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if length < sizeOfBcachestats {
+ return nil, fmt.Errorf("short syscall ret %d bytes", length)
+ }
+ var bcs Bcachestats
+ br := bytes.NewReader(buf)
+ err = common.Read(br, binary.LittleEndian, &bcs)
+ if err != nil {
+ return nil, err
+ }
+ ret.Buffers = uint64(bcs.Numbufpages) * p
+
+ return ret, nil
+}
+
+// Return swapctl summary info
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "swapctl", "-sk")
+ if err != nil {
+ return &SwapMemoryStat{}, nil
+ }
+
+ line := string(out)
+ var total, used, free uint64
+
+ _, err = fmt.Sscanf(line,
+ "total: %d 1K-blocks allocated, %d used, %d available",
+ &total, &used, &free)
+ if err != nil {
+ return nil, errors.New("failed to parse swapctl output")
+ }
+
+ percent := float64(used) / float64(total) * 100
+ return &SwapMemoryStat{
+ Total: total * 1024,
+ Used: used * 1024,
+ Free: free * 1024,
+ UsedPercent: percent,
+ }, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go
new file mode 100644
index 0000000..552e93f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && 386
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+ CTLVfs = 10
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+ Highflips int64
+ Highflops int64
+ Dmaflips int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go
new file mode 100644
index 0000000..73e5b72
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package mem
+
+const (
+ CTLVfs = 10
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfBcachestats = 0x78
+)
+
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go
new file mode 100644
index 0000000..57b5861
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+ CTLVfs = 10
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+ Highflips int64
+ Highflops int64
+ Dmaflips int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go
new file mode 100644
index 0000000..f39a645
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+ CTLVfs = 10
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+ Highflips int64
+ Highflops int64
+ Dmaflips int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go
new file mode 100644
index 0000000..f9f838f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && riscv64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+ CTLVfs = 10
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+ Highflips int64
+ Highflops int64
+ Dmaflips int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go
new file mode 100644
index 0000000..c17a102
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package mem
+
+import (
+ "context"
+ "os"
+
+ stats "github.com/lufia/plan9stats"
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ root := os.Getenv("HOST_ROOT")
+ m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))
+ if err != nil {
+ return nil, err
+ }
+ u := 0.0
+ if m.SwapPages.Avail != 0 {
+ u = float64(m.SwapPages.Used) / float64(m.SwapPages.Avail) * 100.0
+ }
+ return &SwapMemoryStat{
+ Total: uint64(m.SwapPages.Avail * m.PageSize),
+ Used: uint64(m.SwapPages.Used * m.PageSize),
+ Free: uint64(m.SwapPages.Free() * m.PageSize),
+ UsedPercent: u,
+ }, nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ root := os.Getenv("HOST_ROOT")
+ m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))
+ if err != nil {
+ return nil, err
+ }
+ u := 0.0
+ if m.UserPages.Avail != 0 {
+ u = float64(m.UserPages.Used) / float64(m.UserPages.Avail) * 100.0
+ }
+ return &VirtualMemoryStat{
+ Total: uint64(m.Total),
+ Available: uint64(m.UserPages.Free() * m.PageSize),
+ Used: uint64(m.UserPages.Used * m.PageSize),
+ UsedPercent: u,
+ Free: uint64(m.UserPages.Free() * m.PageSize),
+
+ SwapTotal: uint64(m.SwapPages.Avail * m.PageSize),
+ SwapFree: uint64(m.SwapPages.Free() * m.PageSize),
+ }, nil
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go
new file mode 100644
index 0000000..06d0d9a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build solaris
+
+package mem
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/tklauser/go-sysconf"
+)
+
+// VirtualMemory for Solaris is a minimal implementation which only returns
+// what Nomad needs. It does take into account global vs zone, however.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ result := &VirtualMemoryStat{}
+
+ zoneName, err := zoneName()
+ if err != nil {
+ return nil, err
+ }
+
+ if zoneName == "global" {
+ cap, err := globalZoneMemoryCapacity()
+ if err != nil {
+ return nil, err
+ }
+ result.Total = cap
+ freemem, err := globalZoneFreeMemory(ctx)
+ if err != nil {
+ return nil, err
+ }
+ result.Available = freemem
+ result.Free = freemem
+ result.Used = result.Total - result.Free
+ } else {
+ cap, err := nonGlobalZoneMemoryCapacity()
+ if err != nil {
+ return nil, err
+ }
+ result.Total = cap
+ }
+
+ return result, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func zoneName() (string, error) {
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, "zonename")
+ if err != nil {
+ return "", err
+ }
+
+ return strings.TrimSpace(string(out)), nil
+}
+
+var globalZoneMemoryCapacityMatch = regexp.MustCompile(`[Mm]emory size: (\d+) Megabytes`)
+
+func globalZoneMemoryCapacity() (uint64, error) {
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, "prtconf")
+ if err != nil {
+ return 0, err
+ }
+
+ match := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1)
+ if len(match) != 1 {
+ return 0, errors.New("memory size not contained in output of prtconf")
+ }
+
+ totalMB, err := strconv.ParseUint(match[0][1], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ return totalMB * 1024 * 1024, nil
+}
+
+func globalZoneFreeMemory(ctx context.Context) (uint64, error) {
+ output, err := invoke.CommandWithContext(ctx, "pagesize")
+ if err != nil {
+ return 0, err
+ }
+
+ pagesize, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ free, err := sysconf.Sysconf(sysconf.SC_AVPHYS_PAGES)
+ if err != nil {
+ return 0, err
+ }
+
+ return uint64(free) * pagesize, nil
+}
+
+var kstatMatch = regexp.MustCompile(`(\S+)\s+(\S*)`)
+
+func nonGlobalZoneMemoryCapacity() (uint64, error) {
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, "kstat", "-p", "-c", "zone_memory_cap", "memory_cap:*:*:physcap")
+ if err != nil {
+ return 0, err
+ }
+
+ kstats := kstatMatch.FindAllStringSubmatch(string(out), -1)
+ if len(kstats) != 1 {
+ return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats))
+ }
+
+ memSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ return memSizeBytes, nil
+}
+
+const swapCommand = "swap"
+
+// The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html
+const blockSize = 512
+
+// swapctl column indexes
+const (
+ nameCol = 0
+ // devCol = 1
+ // swaploCol = 2
+ totalBlocksCol = 3
+ freeBlocksCol = 4
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ output, err := invoke.CommandWithContext(ctx, swapCommand, "-l")
+ if err != nil {
+ return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
+ }
+
+ return parseSwapsCommandOutput(string(output))
+}
+
+func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) {
+ lines := strings.Split(output, "\n")
+ if len(lines) == 0 {
+ return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
+ }
+
+ // Check header headerFields are as expected.
+ headerFields := strings.Fields(lines[0])
+ if len(headerFields) < freeBlocksCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, lines[0])
+ }
+ if headerFields[nameCol] != "swapfile" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "swapfile")
+ }
+ if headerFields[totalBlocksCol] != "blocks" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalBlocksCol], "blocks")
+ }
+ if headerFields[freeBlocksCol] != "free" {
+ return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[freeBlocksCol], "free")
+ }
+
+ var swapDevices []*SwapDevice
+ for _, line := range lines[1:] {
+ if line == "" {
+ continue // the terminal line is typically empty
+ }
+ fields := strings.Fields(line)
+ if len(fields) < freeBlocksCol {
+ return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
+ }
+
+ totalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
+ }
+
+ freeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
+ }
+
+ swapDevices = append(swapDevices, &SwapDevice{
+ Name: fields[nameCol],
+ UsedBytes: (totalBlocks - freeBlocks) * blockSize,
+ FreeBytes: freeBlocks * blockSize,
+ })
+ }
+
+ return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go
new file mode 100644
index 0000000..a94b61f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package mem
+
+import (
+ "context"
+ "sync"
+ "syscall"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ procEnumPageFilesW = common.ModPsapi.NewProc("EnumPageFilesW")
+ procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
+ procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo")
+ procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
+)
+
+type memoryStatusEx struct {
+ cbSize uint32
+ dwMemoryLoad uint32
+ ullTotalPhys uint64 // in bytes
+ ullAvailPhys uint64
+ ullTotalPageFile uint64
+ ullAvailPageFile uint64
+ ullTotalVirtual uint64
+ ullAvailVirtual uint64
+ ullAvailExtendedVirtual uint64
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ var memInfo memoryStatusEx
+ memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
+ mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
+ if mem == 0 {
+ return nil, windows.GetLastError()
+ }
+
+ ret := &VirtualMemoryStat{
+ Total: memInfo.ullTotalPhys,
+ Available: memInfo.ullAvailPhys,
+ Free: memInfo.ullAvailPhys,
+ UsedPercent: float64(memInfo.dwMemoryLoad),
+ }
+
+ ret.Used = ret.Total - ret.Available
+ return ret, nil
+}
+
+type performanceInformation struct {
+ cb uint32
+ commitTotal uint64
+ commitLimit uint64
+ commitPeak uint64
+ physicalTotal uint64
+ physicalAvailable uint64
+ systemCache uint64
+ kernelTotal uint64
+ kernelPaged uint64
+ kernelNonpaged uint64
+ pageSize uint64
+ handleCount uint32
+ processCount uint32
+ threadCount uint32
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ // Use the performance counter to get the swap usage percentage
+ counter, err := common.NewWin32PerformanceCounter("swap_percentage", `\Paging File(_Total)\% Usage`)
+ if err != nil {
+ return nil, err
+ }
+ defer common.PdhCloseQuery.Call(uintptr(counter.Query))
+
+ usedPercent, err := counter.GetValue()
+ if err != nil {
+ return nil, err
+ }
+
+ // Get total memory from performance information
+ var perfInfo performanceInformation
+ perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
+ mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
+ if mem == 0 {
+ return nil, windows.GetLastError()
+ }
+ totalPhys := perfInfo.physicalTotal * perfInfo.pageSize
+ totalSys := perfInfo.commitLimit * perfInfo.pageSize
+ total := totalSys - totalPhys
+
+ var used uint64
+ if total > 0 {
+ used = uint64(0.01 * usedPercent * float64(total))
+ } else {
+ usedPercent = 0.0
+ used = 0
+ }
+
+ ret := &SwapMemoryStat{
+ Total: total,
+ Used: used,
+ Free: total - used,
+ UsedPercent: common.Round(usedPercent, 1),
+ }
+
+ return ret, nil
+}
+
+var (
+ pageSize uint64
+ pageSizeOnce sync.Once
+)
+
+type systemInfo struct {
+ wProcessorArchitecture uint16
+ wReserved uint16
+ dwPageSize uint32
+ lpMinimumApplicationAddress uintptr
+ lpMaximumApplicationAddress uintptr
+ dwActiveProcessorMask uintptr
+ dwNumberOfProcessors uint32
+ dwProcessorType uint32
+ dwAllocationGranularity uint32
+ wProcessorLevel uint16
+ wProcessorRevision uint16
+}
+
+// system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information
+type enumPageFileInformation struct {
+ cb uint32
+ reserved uint32
+ totalSize uint64
+ totalInUse uint64
+ peakUsage uint64
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+ return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+ pageSizeOnce.Do(func() {
+ var sysInfo systemInfo
+ procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))
+ pageSize = uint64(sysInfo.dwPageSize)
+ })
+
+ // the following system call invokes the supplied callback function once for each page file before returning
+ // see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw
+ var swapDevices []*SwapDevice
+ result, _, _ := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices)))
+ if result == 0 {
+ return nil, windows.GetLastError()
+ }
+
+ return swapDevices, nil
+}
+
+// system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw
+func pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool {
+ *swapDevices = append(*swapDevices, &SwapDevice{
+ Name: syscall.UTF16ToString((*lpFilenamePtr)[:]),
+ UsedBytes: enumPageFileInfo.totalInUse * pageSize,
+ FreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize,
+ })
+
+ // return true to continue enumerating page files
+ ret := true
+ return &ret
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net.go b/vendor/github.com/shirou/gopsutil/v4/net/net.go
new file mode 100644
index 0000000..74af54a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net.go
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package net
+
+import (
+ "context"
+ "encoding/json"
+ "net"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+type IOCountersStat struct {
+ Name string `json:"name"` // interface name
+ BytesSent uint64 `json:"bytesSent"` // number of bytes sent
+ BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
+ PacketsSent uint64 `json:"packetsSent"` // number of packets sent
+ PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
+ Errin uint64 `json:"errin"` // total number of errors while receiving
+ Errout uint64 `json:"errout"` // total number of errors while sending
+ Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
+ Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
+ Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
+ Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
+}
+
+// Addr is implemented compatibility to psutil
+type Addr struct {
+ IP string `json:"ip"`
+ Port uint32 `json:"port"`
+}
+
+type ConnectionStat struct {
+ Fd uint32 `json:"fd"`
+ Family uint32 `json:"family"`
+ Type uint32 `json:"type"`
+ Laddr Addr `json:"localaddr"`
+ Raddr Addr `json:"remoteaddr"`
+ Status string `json:"status"`
+ Uids []int32 `json:"uids"`
+ Pid int32 `json:"pid"`
+}
+
+// System wide stats about different network protocols
+type ProtoCountersStat struct {
+ Protocol string `json:"protocol"`
+ Stats map[string]int64 `json:"stats"`
+}
+
+// NetInterfaceAddr is designed for represent interface addresses
+type InterfaceAddr struct {
+ Addr string `json:"addr"`
+}
+
+// InterfaceAddrList is a list of InterfaceAddr
+type InterfaceAddrList []InterfaceAddr
+
+type InterfaceStat struct {
+ Index int `json:"index"`
+ MTU int `json:"mtu"` // maximum transmission unit
+ Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr string `json:"hardwareAddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
+ Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
+ Addrs InterfaceAddrList `json:"addrs"`
+}
+
+// InterfaceStatList is a list of InterfaceStat
+type InterfaceStatList []InterfaceStat
+
+type FilterStat struct {
+ ConnTrackCount int64 `json:"connTrackCount"`
+ ConnTrackMax int64 `json:"connTrackMax"`
+}
+
+// ConntrackStat has conntrack summary info
+type ConntrackStat struct {
+ Entries uint32 `json:"entries"` // Number of entries in the conntrack table
+ Searched uint32 `json:"searched"` // Number of conntrack table lookups performed
+ Found uint32 `json:"found"` // Number of searched entries which were successful
+ New uint32 `json:"new"` // Number of entries added which were not expected before
+ Invalid uint32 `json:"invalid"` // Number of packets seen which can not be tracked
+ Ignore uint32 `json:"ignore"` // Packets seen which are already connected to an entry
+ Delete uint32 `json:"delete"` // Number of entries which were removed
+ DeleteList uint32 `json:"deleteList"` // Number of entries which were put to dying list
+ Insert uint32 `json:"insert"` // Number of entries inserted into the list
+ InsertFailed uint32 `json:"insertFailed"` // # insertion attempted but failed (same entry exists)
+ Drop uint32 `json:"drop"` // Number of packets dropped due to conntrack failure.
+ EarlyDrop uint32 `json:"earlyDrop"` // Dropped entries to make room for new ones, if maxsize reached
+ IcmpError uint32 `json:"icmpError"` // Subset of invalid. Packets that can't be tracked d/t error
+ ExpectNew uint32 `json:"expectNew"` // Entries added after an expectation was already present
+ ExpectCreate uint32 `json:"expectCreate"` // Expectations added
+ ExpectDelete uint32 `json:"expectDelete"` // Expectations deleted
+ SearchRestart uint32 `json:"searchRestart"` // Conntrack table lookups restarted due to hashtable resizes
+}
+
+func NewConntrackStat(e uint32, s uint32, f uint32, n uint32, inv uint32, ign uint32, del uint32, dlst uint32, ins uint32, insfail uint32, drop uint32, edrop uint32, ie uint32, en uint32, ec uint32, ed uint32, sr uint32) *ConntrackStat {
+ return &ConntrackStat{
+ Entries: e,
+ Searched: s,
+ Found: f,
+ New: n,
+ Invalid: inv,
+ Ignore: ign,
+ Delete: del,
+ DeleteList: dlst,
+ Insert: ins,
+ InsertFailed: insfail,
+ Drop: drop,
+ EarlyDrop: edrop,
+ IcmpError: ie,
+ ExpectNew: en,
+ ExpectCreate: ec,
+ ExpectDelete: ed,
+ SearchRestart: sr,
+ }
+}
+
+type ConntrackStatList struct {
+ items []*ConntrackStat
+}
+
+func NewConntrackStatList() *ConntrackStatList {
+ return &ConntrackStatList{
+ items: []*ConntrackStat{},
+ }
+}
+
+func (l *ConntrackStatList) Append(c *ConntrackStat) {
+ l.items = append(l.items, c)
+}
+
+func (l *ConntrackStatList) Items() []ConntrackStat {
+ items := make([]ConntrackStat, len(l.items))
+ for i, el := range l.items {
+ items[i] = *el
+ }
+ return items
+}
+
+// Summary returns a single-element list with totals from all list items.
+func (l *ConntrackStatList) Summary() []ConntrackStat {
+ summary := NewConntrackStat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ for _, cs := range l.items {
+ summary.Entries += cs.Entries
+ summary.Searched += cs.Searched
+ summary.Found += cs.Found
+ summary.New += cs.New
+ summary.Invalid += cs.Invalid
+ summary.Ignore += cs.Ignore
+ summary.Delete += cs.Delete
+ summary.DeleteList += cs.DeleteList
+ summary.Insert += cs.Insert
+ summary.InsertFailed += cs.InsertFailed
+ summary.Drop += cs.Drop
+ summary.EarlyDrop += cs.EarlyDrop
+ summary.IcmpError += cs.IcmpError
+ summary.ExpectNew += cs.ExpectNew
+ summary.ExpectCreate += cs.ExpectCreate
+ summary.ExpectDelete += cs.ExpectDelete
+ summary.SearchRestart += cs.SearchRestart
+ }
+ return []ConntrackStat{*summary}
+}
+
+func (n IOCountersStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n ConnectionStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n ProtoCountersStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (a Addr) String() string {
+ s, _ := json.Marshal(a)
+ return string(s)
+}
+
+func (n InterfaceStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (l InterfaceStatList) String() string {
+ s, _ := json.Marshal(l)
+ return string(s)
+}
+
+func (n InterfaceAddr) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n ConntrackStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func Interfaces() (InterfaceStatList, error) {
+ return InterfacesWithContext(context.Background())
+}
+
+func InterfacesWithContext(ctx context.Context) (InterfaceStatList, error) {
+ is, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ ret := make(InterfaceStatList, 0, len(is))
+ for _, ifi := range is {
+
+ var flags []string
+ if ifi.Flags&net.FlagUp != 0 {
+ flags = append(flags, "up")
+ }
+ if ifi.Flags&net.FlagBroadcast != 0 {
+ flags = append(flags, "broadcast")
+ }
+ if ifi.Flags&net.FlagLoopback != 0 {
+ flags = append(flags, "loopback")
+ }
+ if ifi.Flags&net.FlagPointToPoint != 0 {
+ flags = append(flags, "pointtopoint")
+ }
+ if ifi.Flags&net.FlagMulticast != 0 {
+ flags = append(flags, "multicast")
+ }
+
+ r := InterfaceStat{
+ Index: ifi.Index,
+ Name: ifi.Name,
+ MTU: ifi.MTU,
+ HardwareAddr: ifi.HardwareAddr.String(),
+ Flags: flags,
+ }
+ addrs, err := ifi.Addrs()
+ if err == nil {
+ r.Addrs = make(InterfaceAddrList, 0, len(addrs))
+ for _, addr := range addrs {
+ r.Addrs = append(r.Addrs, InterfaceAddr{
+ Addr: addr.String(),
+ })
+ }
+
+ }
+ ret = append(ret, r)
+ }
+
+ return ret, nil
+}
+
+func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) {
+ r := IOCountersStat{
+ Name: "all",
+ }
+ for _, nic := range n {
+ r.BytesRecv += nic.BytesRecv
+ r.PacketsRecv += nic.PacketsRecv
+ r.Errin += nic.Errin
+ r.Dropin += nic.Dropin
+ r.BytesSent += nic.BytesSent
+ r.PacketsSent += nic.PacketsSent
+ r.Errout += nic.Errout
+ r.Dropout += nic.Dropout
+ }
+
+ return []IOCountersStat{r}, nil
+}
+
+// NetIOCounters returns network I/O statistics for every network
+// interface installed on the system. If pernic argument is false,
+// return only sum of all information (which name is 'all'). If true,
+// every network interface installed on the system is returned
+// separately.
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+// ProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Available protocols:
+// [ip,icmp,icmpmsg,tcp,udp,udplite]
+// Not Implemented for FreeBSD, Windows, OpenBSD, Darwin
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+// NetFilterCounters returns iptables conntrack statistics
+// the currently in use conntrack count and the max.
+// If the file does not exist or is invalid it will return nil.
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+// ConntrackStats returns more detailed info about the conntrack table
+func ConntrackStats(percpu bool) ([]ConntrackStat, error) {
+ return ConntrackStatsWithContext(context.Background(), percpu)
+}
+
+// Return a list of network connections opened.
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+// Return a list of network connections opened returning at most `max`
+// connections for each running process.
+func ConnectionsMax(kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithContext(context.Background(), kind, maxConn)
+}
+
+// Return a list of network connections opened, omitting `Uids`.
+// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
+// removed from the API in the future.
+func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithoutUidsWithContext(context.Background(), kind)
+}
+
+// Return a list of network connections opened by a process.
+func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(context.Background(), kind, pid)
+}
+
+// Return a list of network connections opened, omitting `Uids`.
+// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
+// removed from the API in the future.
+func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid)
+}
+
+func ConnectionsPidMaxWithoutUids(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, maxConn)
+}
+
+// Return up to `max` network connections opened by a process.
+func ConnectionsPidMax(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(context.Background(), kind, pid, maxConn)
+}
+
+// Pids retunres all pids.
+// Note: this is a copy of process_linux.Pids()
+// FIXME: Import process occures import cycle.
+// move to common made other platform breaking. Need consider.
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go
new file mode 100644
index 0000000..9df01e3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func parseNetstatNetLine(line string) (ConnectionStat, error) {
+ f := strings.Fields(line)
+ if len(f) < 5 {
+ return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+ }
+
+ var netType, netFamily uint32
+ switch f[0] {
+ case "tcp", "tcp4":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET
+ case "udp", "udp4":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET
+ case "tcp6":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET6
+ case "udp6":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET6
+ default:
+ return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+ }
+
+ laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+ }
+
+ n := ConnectionStat{
+ Fd: uint32(0), // not supported
+ Family: uint32(netFamily),
+ Type: uint32(netType),
+ Laddr: laddr,
+ Raddr: raddr,
+ Pid: int32(0), // not supported
+ }
+ if len(f) == 6 {
+ n.Status = f[5]
+ }
+
+ return n, nil
+}
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+// This function only works for netstat returning addresses with a "."
+// before the port (0.0.0.0.22 instead of 0.0.0.0:22).
+func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
+ parse := func(l string) (Addr, error) {
+ matches := portMatch.FindStringSubmatch(l)
+ if matches == nil {
+ return Addr{}, fmt.Errorf("wrong addr, %s", l)
+ }
+ host := matches[1]
+ port := matches[2]
+ if host == "*" {
+ switch family {
+ case syscall.AF_INET:
+ host = "0.0.0.0"
+ case syscall.AF_INET6:
+ host = "::"
+ default:
+ return Addr{}, fmt.Errorf("unknown family, %d", family)
+ }
+ }
+ lport, err := strconv.ParseInt(port, 10, 32)
+ if err != nil {
+ return Addr{}, err
+ }
+ return Addr{IP: host, Port: uint32(lport)}, nil
+ }
+
+ laddr, err = parse(local)
+ if remote != "*.*" { // remote addr exists
+ raddr, err = parse(remote)
+ if err != nil {
+ return laddr, raddr, err
+ }
+ }
+
+ return laddr, raddr, err
+}
+
+func parseNetstatUnixLine(f []string) (ConnectionStat, error) {
+ if len(f) < 8 {
+ return ConnectionStat{}, fmt.Errorf("wrong number of fields: expected >=8 got %d", len(f))
+ }
+
+ var netType uint32
+
+ switch f[1] {
+ case "dgram":
+ netType = syscall.SOCK_DGRAM
+ case "stream":
+ netType = syscall.SOCK_STREAM
+ default:
+ return ConnectionStat{}, fmt.Errorf("unknown type: %s", f[1])
+ }
+
+ // Some Unix Socket don't have any address associated
+ addr := ""
+ if len(f) == 9 {
+ addr = f[8]
+ }
+
+ c := ConnectionStat{
+ Fd: uint32(0), // not supported
+ Family: uint32(syscall.AF_UNIX),
+ Type: uint32(netType),
+ Laddr: Addr{
+ IP: addr,
+ },
+ Status: "NONE",
+ Pid: int32(0), // not supported
+ }
+
+ return c, nil
+}
+
+// Return true if proto is the corresponding to the kind parameter
+// Only for Inet lines
+func hasCorrectInetProto(kind, proto string) bool {
+ switch kind {
+ case "all", "inet":
+ return true
+ case "unix":
+ return false
+ case "inet4":
+ return !strings.HasSuffix(proto, "6")
+ case "inet6":
+ return strings.HasSuffix(proto, "6")
+ case "tcp":
+ return proto == "tcp" || proto == "tcp4" || proto == "tcp6"
+ case "tcp4":
+ return proto == "tcp" || proto == "tcp4"
+ case "tcp6":
+ return proto == "tcp6"
+ case "udp":
+ return proto == "udp" || proto == "udp4" || proto == "udp6"
+ case "udp4":
+ return proto == "udp" || proto == "udp4"
+ case "udp6":
+ return proto == "udp6"
+ }
+ return false
+}
+
+func parseNetstatA(output string, kind string) ([]ConnectionStat, error) {
+ var ret []ConnectionStat
+ lines := strings.Split(string(output), "\n")
+
+ for _, line := range lines {
+ fields := strings.Fields(line)
+ if len(fields) < 1 {
+ continue
+ }
+
+ if strings.HasPrefix(fields[0], "f1") {
+ // Unix lines
+ if len(fields) < 2 {
+ // every unix connections have two lines
+ continue
+ }
+
+ c, err := parseNetstatUnixLine(fields)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse Unix Address (%s): %s", line, err)
+ }
+
+ ret = append(ret, c)
+
+ } else if strings.HasPrefix(fields[0], "tcp") || strings.HasPrefix(fields[0], "udp") {
+ // Inet lines
+ if !hasCorrectInetProto(kind, fields[0]) {
+ continue
+ }
+
+ // On AIX, netstat display some connections with "*.*" as local addresses
+ // Skip them as they aren't real connections.
+ if fields[3] == "*.*" {
+ continue
+ }
+
+ c, err := parseNetstatNetLine(line)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse Inet Address (%s): %s", line, err)
+ }
+
+ ret = append(ret, c)
+ } else {
+ // Header lines
+ continue
+ }
+ }
+
+ return ret, nil
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ args := []string{"-na"}
+ switch strings.ToLower(kind) {
+ default:
+ fallthrough
+ case "":
+ kind = "all"
+ case "all":
+ // nothing to add
+ case "inet", "inet4", "inet6":
+ args = append(args, "-finet")
+ case "tcp", "tcp4", "tcp6":
+ args = append(args, "-finet")
+ case "udp", "udp4", "udp6":
+ args = append(args, "-finet")
+ case "unix":
+ args = append(args, "-funix")
+ }
+
+ out, err := invoke.CommandWithContext(ctx, "netstat", args...)
+ if err != nil {
+ return nil, err
+ }
+
+ ret, err := parseNetstatA(string(out), kind)
+ if err != nil {
+ return nil, err
+ }
+
+ return ret, nil
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int, skipUids bool) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go
new file mode 100644
index 0000000..a45a5b7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package net
+
+import (
+ "context"
+
+ "github.com/power-devops/perfstat"
+)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ ifs, err := perfstat.NetIfaceStat()
+ if err != nil {
+ return nil, err
+ }
+
+ iocounters := make([]IOCountersStat, 0, len(ifs))
+ for _, netif := range ifs {
+ n := IOCountersStat{
+ Name: netif.Name,
+ BytesSent: uint64(netif.OBytes),
+ BytesRecv: uint64(netif.IBytes),
+ PacketsSent: uint64(netif.OPackets),
+ PacketsRecv: uint64(netif.IPackets),
+ Errin: uint64(netif.OErrors),
+ Errout: uint64(netif.IErrors),
+ Dropout: uint64(netif.XmitDrops),
+ }
+ iocounters = append(iocounters, n)
+ }
+ if pernic == false {
+ return getIOCountersAll(iocounters)
+ }
+ return iocounters, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go
new file mode 100644
index 0000000..f63a21e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func parseNetstatI(output string) ([]IOCountersStat, error) {
+ lines := strings.Split(string(output), "\n")
+ ret := make([]IOCountersStat, 0, len(lines)-1)
+ exists := make([]string, 0, len(ret))
+
+ // Check first line is header
+ if len(lines) > 0 && strings.Fields(lines[0])[0] != "Name" {
+ return nil, fmt.Errorf("not a 'netstat -i' output")
+ }
+
+ for _, line := range lines[1:] {
+ values := strings.Fields(line)
+ if len(values) < 1 || values[0] == "Name" {
+ continue
+ }
+ if common.StringsHas(exists, values[0]) {
+ // skip if already get
+ continue
+ }
+ exists = append(exists, values[0])
+
+ if len(values) < 9 {
+ continue
+ }
+
+ base := 1
+ // sometimes Address is omitted
+ if len(values) < 10 {
+ base = 0
+ }
+
+ parsed := make([]uint64, 0, 5)
+ vv := []string{
+ values[base+3], // Ipkts == PacketsRecv
+ values[base+4], // Ierrs == Errin
+ values[base+5], // Opkts == PacketsSent
+ values[base+6], // Oerrs == Errout
+ values[base+8], // Drops == Dropout
+ }
+
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ t, err := strconv.ParseUint(target, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ parsed = append(parsed, t)
+ }
+
+ n := IOCountersStat{
+ Name: values[0],
+ PacketsRecv: parsed[0],
+ Errin: parsed[1],
+ PacketsSent: parsed[2],
+ Errout: parsed[3],
+ Dropout: parsed[4],
+ }
+ ret = append(ret, n)
+ }
+ return ret, nil
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "netstat", "-idn")
+ if err != nil {
+ return nil, err
+ }
+
+ iocounters, err := parseNetstatI(string(out))
+ if err != nil {
+ return nil, err
+ }
+ if pernic == false {
+ return getIOCountersAll(iocounters)
+ }
+ return iocounters, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go b/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go
new file mode 100644
index 0000000..86c541e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package net
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+ errNetstatHeader = errors.New("Can't parse header of netstat output")
+ netstatLinkRegexp = regexp.MustCompile(`^<Link#(\d+)>$`)
+)
+
+const endOfLine = "\n"
+
+func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) {
+ var (
+ numericValue uint64
+ columns = strings.Fields(line)
+ )
+
+ if columns[0] == "Name" {
+ err = errNetstatHeader
+ return
+ }
+
+ // try to extract the numeric value from <Link#123>
+ if subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 {
+ numericValue, err = strconv.ParseUint(subMatch[1], 10, 64)
+ if err != nil {
+ return
+ }
+ linkIDUint := uint(numericValue)
+ linkID = &linkIDUint
+ }
+
+ base := 1
+ numberColumns := len(columns)
+ // sometimes Address is omitted
+ if numberColumns < 12 {
+ base = 0
+ }
+ if numberColumns < 11 || numberColumns > 13 {
+ err = fmt.Errorf("Line %q do have an invalid number of columns %d", line, numberColumns)
+ return
+ }
+
+ parsed := make([]uint64, 0, 7)
+ vv := []string{
+ columns[base+3], // Ipkts == PacketsRecv
+ columns[base+4], // Ierrs == Errin
+ columns[base+5], // Ibytes == BytesRecv
+ columns[base+6], // Opkts == PacketsSent
+ columns[base+7], // Oerrs == Errout
+ columns[base+8], // Obytes == BytesSent
+ }
+ if len(columns) == 12 {
+ vv = append(vv, columns[base+10])
+ }
+
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ if numericValue, err = strconv.ParseUint(target, 10, 64); err != nil {
+ return
+ }
+ parsed = append(parsed, numericValue)
+ }
+
+ stat = &IOCountersStat{
+ Name: strings.Trim(columns[0], "*"), // remove the * that sometimes is on right on interface
+ PacketsRecv: parsed[0],
+ Errin: parsed[1],
+ BytesRecv: parsed[2],
+ PacketsSent: parsed[3],
+ Errout: parsed[4],
+ BytesSent: parsed[5],
+ }
+ if len(parsed) == 7 {
+ stat.Dropout = parsed[6]
+ }
+ return
+}
+
+type netstatInterface struct {
+ linkID *uint
+ stat *IOCountersStat
+}
+
+func parseNetstatOutput(output string) ([]netstatInterface, error) {
+ var (
+ err error
+ lines = strings.Split(strings.Trim(output, endOfLine), endOfLine)
+ )
+
+ // number of interfaces is number of lines less one for the header
+ numberInterfaces := len(lines) - 1
+
+ interfaces := make([]netstatInterface, numberInterfaces)
+ // no output beside header
+ if numberInterfaces == 0 {
+ return interfaces, nil
+ }
+
+ for index := 0; index < numberInterfaces; index++ {
+ nsIface := netstatInterface{}
+ if nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil {
+ return nil, err
+ }
+ interfaces[index] = nsIface
+ }
+ return interfaces, nil
+}
+
+// map that hold the name of a network interface and the number of usage
+type mapInterfaceNameUsage map[string]uint
+
+func newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage {
+ output := make(mapInterfaceNameUsage)
+ for index := range ifaces {
+ if ifaces[index].linkID != nil {
+ ifaceName := ifaces[index].stat.Name
+ usage, ok := output[ifaceName]
+ if ok {
+ output[ifaceName] = usage + 1
+ } else {
+ output[ifaceName] = 1
+ }
+ }
+ }
+ return output
+}
+
+func (mapi mapInterfaceNameUsage) isTruncated() bool {
+ for _, usage := range mapi {
+ if usage > 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func (mapi mapInterfaceNameUsage) notTruncated() []string {
+ output := make([]string, 0)
+ for ifaceName, usage := range mapi {
+ if usage == 1 {
+ output = append(output, ifaceName)
+ }
+ }
+ return output
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+// example of `netstat -ibdnW` output on yosemite
+// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
+// lo0 16384 <Link#1> 869107 0 169411755 869107 0 169411755 0 0
+// lo0 16384 ::1/128 ::1 869107 - 169411755 869107 - 169411755 - -
+// lo0 16384 127 127.0.0.1 869107 - 169411755 869107 - 169411755 - -
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ var (
+ ret []IOCountersStat
+ retIndex int
+ )
+
+ netstat, err := exec.LookPath("netstat")
+ if err != nil {
+ return nil, err
+ }
+
+ // try to get all interface metrics, and hope there won't be any truncated
+ out, err := invoke.CommandWithContext(ctx, netstat, "-ibdnW")
+ if err != nil {
+ return nil, err
+ }
+
+ nsInterfaces, err := parseNetstatOutput(string(out))
+ if err != nil {
+ return nil, err
+ }
+
+ ifaceUsage := newMapInterfaceNameUsage(nsInterfaces)
+ notTruncated := ifaceUsage.notTruncated()
+ ret = make([]IOCountersStat, len(notTruncated))
+
+ if !ifaceUsage.isTruncated() {
+ // no truncated interface name, return stats of all interface with <Link#...>
+ for index := range nsInterfaces {
+ if nsInterfaces[index].linkID != nil {
+ ret[retIndex] = *nsInterfaces[index].stat
+ retIndex++
+ }
+ }
+ } else {
+ // duplicated interface, list all interfaces
+ if out, err = invoke.CommandWithContext(ctx, "ifconfig", "-l"); err != nil {
+ return nil, err
+ }
+ interfaceNames := strings.Fields(strings.TrimRight(string(out), endOfLine))
+
+ // for each of the interface name, run netstat if we don't have any stats yet
+ for _, interfaceName := range interfaceNames {
+ truncated := true
+ for index := range nsInterfaces {
+ if nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName {
+ // handle the non truncated name to avoid execute netstat for them again
+ ret[retIndex] = *nsInterfaces[index].stat
+ retIndex++
+ truncated = false
+ break
+ }
+ }
+ if truncated {
+ // run netstat with -I$ifacename
+ if out, err = invoke.CommandWithContext(ctx, netstat, "-ibdnWI"+interfaceName); err != nil {
+ return nil, err
+ }
+ parsedIfaces, err := parseNetstatOutput(string(out))
+ if err != nil {
+ return nil, err
+ }
+ if len(parsedIfaces) == 0 {
+ // interface had been removed since `ifconfig -l` had been executed
+ continue
+ }
+ for index := range parsedIfaces {
+ if parsedIfaces[index].linkID != nil {
+ ret = append(ret, *parsedIfaces[index].stat)
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if !pernic {
+ return getIOCountersAll(ret)
+ }
+ return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go b/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go
new file mode 100644
index 0000000..7d7596a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !aix && !darwin && !linux && !freebsd && !openbsd && !windows && !solaris
+
+package net
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ return []IOCountersStat{}, common.ErrNotImplementedError
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go
new file mode 100644
index 0000000..655e133
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package net
+
+import (
+ "context"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ out, err := invoke.CommandWithContext(ctx, "netstat", "-ibdnW")
+ if err != nil {
+ return nil, err
+ }
+
+ lines := strings.Split(string(out), "\n")
+ ret := make([]IOCountersStat, 0, len(lines)-1)
+ exists := make([]string, 0, len(ret))
+
+ for _, line := range lines {
+ values := strings.Fields(line)
+ if len(values) < 1 || values[0] == "Name" {
+ continue
+ }
+ if common.StringsHas(exists, values[0]) {
+ // skip if already get
+ continue
+ }
+ exists = append(exists, values[0])
+
+ if len(values) < 12 {
+ continue
+ }
+ base := 1
+ // sometimes Address is omitted
+ if len(values) < 13 {
+ base = 0
+ }
+
+ parsed := make([]uint64, 0, 8)
+ vv := []string{
+ values[base+3], // PacketsRecv
+ values[base+4], // Errin
+ values[base+5], // Dropin
+ values[base+6], // BytesRecvn
+ values[base+7], // PacketSent
+ values[base+8], // Errout
+ values[base+9], // BytesSent
+ values[base+11], // Dropout
+ }
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ t, err := strconv.ParseUint(target, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ parsed = append(parsed, t)
+ }
+
+ n := IOCountersStat{
+ Name: values[0],
+ PacketsRecv: parsed[0],
+ Errin: parsed[1],
+ Dropin: parsed[2],
+ BytesRecv: parsed[3],
+ PacketsSent: parsed[4],
+ Errout: parsed[5],
+ BytesSent: parsed[6],
+ Dropout: parsed[7],
+ }
+ ret = append(ret, n)
+ }
+
+ if !pernic {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go b/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go
new file mode 100644
index 0000000..23113fe
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go
@@ -0,0 +1,807 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package net
+
+import (
+ "bytes"
+ "context"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+const ( // Conntrack Column numbers
+ ctENTRIES = iota
+ ctSEARCHED
+ ctFOUND
+ ctNEW
+ ctINVALID
+ ctIGNORE
+ ctDELETE
+ ctDELETE_LIST
+ ctINSERT
+ ctINSERT_FAILED
+ ctDROP
+ ctEARLY_DROP
+ ctICMP_ERROR
+ CT_EXPEctNEW
+ ctEXPECT_CREATE
+ CT_EXPEctDELETE
+ ctSEARCH_RESTART
+)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ filename := common.HostProcWithContext(ctx, "net/dev")
+ return IOCountersByFileWithContext(ctx, pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ parts := make([]string, 2)
+
+ statlen := len(lines) - 1
+
+ ret := make([]IOCountersStat, 0, statlen)
+
+ for _, line := range lines[2:] {
+ separatorPos := strings.LastIndex(line, ":")
+ if separatorPos == -1 {
+ continue
+ }
+ parts[0] = line[0:separatorPos]
+ parts[1] = line[separatorPos+1:]
+
+ interfaceName := strings.TrimSpace(parts[0])
+ if interfaceName == "" {
+ continue
+ }
+
+ fields := strings.Fields(strings.TrimSpace(parts[1]))
+ bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ packetsRecv, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ errIn, err := strconv.ParseUint(fields[2], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ dropIn, err := strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ packetsSent, err := strconv.ParseUint(fields[9], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ errOut, err := strconv.ParseUint(fields[10], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ dropOut, err := strconv.ParseUint(fields[11], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ fifoOut, err := strconv.ParseUint(fields[12], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+
+ nic := IOCountersStat{
+ Name: interfaceName,
+ BytesRecv: bytesRecv,
+ PacketsRecv: packetsRecv,
+ Errin: errIn,
+ Dropin: dropIn,
+ Fifoin: fifoIn,
+ BytesSent: bytesSent,
+ PacketsSent: packetsSent,
+ Errout: errOut,
+ Dropout: dropOut,
+ Fifoout: fifoOut,
+ }
+ ret = append(ret, nic)
+ }
+
+ if !pernic {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+var netProtocols = []string{
+ "ip",
+ "icmp",
+ "icmpmsg",
+ "tcp",
+ "udp",
+ "udplite",
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ if len(protocols) == 0 {
+ protocols = netProtocols
+ }
+
+ stats := make([]ProtoCountersStat, 0, len(protocols))
+ protos := make(map[string]bool, len(protocols))
+ for _, p := range protocols {
+ protos[p] = true
+ }
+
+ filename := common.HostProcWithContext(ctx, "net/snmp")
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ linecount := len(lines)
+ for i := 0; i < linecount; i++ {
+ line := lines[i]
+ r := strings.IndexRune(line, ':')
+ if r == -1 {
+ return nil, errors.New(filename + " is not formatted correctly, expected ':'.")
+ }
+ proto := strings.ToLower(line[:r])
+ if !protos[proto] {
+ // skip protocol and data line
+ i++
+ continue
+ }
+
+ // Read header line
+ statNames := strings.Split(line[r+2:], " ")
+
+ // Read data line
+ i++
+ statValues := strings.Split(lines[i][r+2:], " ")
+ if len(statNames) != len(statValues) {
+ return nil, errors.New(filename + " is not formatted correctly, expected same number of columns.")
+ }
+ stat := ProtoCountersStat{
+ Protocol: proto,
+ Stats: make(map[string]int64, len(statNames)),
+ }
+ for j := range statNames {
+ value, err := strconv.ParseInt(statValues[j], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ stat.Stats[statNames[j]] = value
+ }
+ stats = append(stats, stat)
+ }
+ return stats, nil
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ countfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_count")
+ maxfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_max")
+
+ count, err := common.ReadInts(countfile)
+ if err != nil {
+ return nil, err
+ }
+ stats := make([]FilterStat, 0, 1)
+
+ maxConn, err := common.ReadInts(maxfile)
+ if err != nil {
+ return nil, err
+ }
+
+ payload := FilterStat{
+ ConnTrackCount: count[0],
+ ConnTrackMax: maxConn[0],
+ }
+
+ stats = append(stats, payload)
+ return stats, nil
+}
+
+// ConntrackStatsWithContext returns more detailed info about the conntrack table
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return conntrackStatsFromFile(common.HostProcWithContext(ctx, "net/stat/nf_conntrack"), percpu)
+}
+
+// conntrackStatsFromFile returns more detailed info about the conntrack table
+// from `filename`
+// If 'percpu' is false, the result will contain exactly one item with totals/summary
+func conntrackStatsFromFile(filename string, percpu bool) ([]ConntrackStat, error) {
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ statlist := NewConntrackStatList()
+
+ for _, line := range lines {
+ fields := strings.Fields(line)
+ if len(fields) == 17 && fields[0] != "entries" {
+ statlist.Append(NewConntrackStat(
+ common.HexToUint32(fields[ctENTRIES]),
+ common.HexToUint32(fields[ctSEARCHED]),
+ common.HexToUint32(fields[ctFOUND]),
+ common.HexToUint32(fields[ctNEW]),
+ common.HexToUint32(fields[ctINVALID]),
+ common.HexToUint32(fields[ctIGNORE]),
+ common.HexToUint32(fields[ctDELETE]),
+ common.HexToUint32(fields[ctDELETE_LIST]),
+ common.HexToUint32(fields[ctINSERT]),
+ common.HexToUint32(fields[ctINSERT_FAILED]),
+ common.HexToUint32(fields[ctDROP]),
+ common.HexToUint32(fields[ctEARLY_DROP]),
+ common.HexToUint32(fields[ctICMP_ERROR]),
+ common.HexToUint32(fields[CT_EXPEctNEW]),
+ common.HexToUint32(fields[ctEXPECT_CREATE]),
+ common.HexToUint32(fields[CT_EXPEctDELETE]),
+ common.HexToUint32(fields[ctSEARCH_RESTART]),
+ ))
+ }
+ }
+
+ if percpu {
+ return statlist.Items(), nil
+ }
+ return statlist.Summary(), nil
+}
+
+// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
+var tcpStatuses = map[string]string{
+ "01": "ESTABLISHED",
+ "02": "SYN_SENT",
+ "03": "SYN_RECV",
+ "04": "FIN_WAIT1",
+ "05": "FIN_WAIT2",
+ "06": "TIME_WAIT",
+ "07": "CLOSE",
+ "08": "CLOSE_WAIT",
+ "09": "LAST_ACK",
+ "0A": "LISTEN",
+ "0B": "CLOSING",
+}
+
+type netConnectionKindType struct {
+ family uint32
+ sockType uint32
+ filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp",
+}
+
+var kindTCP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp6",
+}
+
+var kindUDP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp",
+}
+
+var kindUDP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp6",
+}
+
+var kindUNIX = netConnectionKindType{
+ family: syscall.AF_UNIX,
+ filename: "unix",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
+ "tcp": {kindTCP4, kindTCP6},
+ "tcp4": {kindTCP4},
+ "tcp6": {kindTCP6},
+ "udp": {kindUDP4, kindUDP6},
+ "udp4": {kindUDP4},
+ "udp6": {kindUDP6},
+ "unix": {kindUNIX},
+ "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "inet4": {kindTCP4, kindUDP4},
+ "inet6": {kindTCP6, kindUDP6},
+}
+
+type inodeMap struct {
+ pid int32
+ fd uint32
+}
+
+type connTmp struct {
+ fd uint32
+ family uint32
+ sockType uint32
+ laddr Addr
+ raddr Addr
+ status string
+ pid int32
+ boundPid int32
+ path string
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int, skipUids bool) ([]ConnectionStat, error) {
+ tmap, ok := netConnectionKindMap[kind]
+ if !ok {
+ return nil, fmt.Errorf("invalid kind, %s", kind)
+ }
+ root := common.HostProcWithContext(ctx)
+ var err error
+ var inodes map[string][]inodeMap
+ if pid == 0 {
+ inodes, err = getProcInodesAllWithContext(ctx, root, maxConn)
+ } else {
+ inodes, err = getProcInodes(root, pid, maxConn)
+ if len(inodes) == 0 {
+ // no connection for the pid
+ return []ConnectionStat{}, nil
+ }
+ }
+ if err != nil {
+ return nil, fmt.Errorf("could not get pid(s), %d: %w", pid, err)
+ }
+ return statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids)
+}
+
+func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {
+ dupCheckMap := make(map[string]struct{})
+ var ret []ConnectionStat
+
+ var err error
+ for _, t := range tmap {
+ var path string
+ var connKey string
+ var ls []connTmp
+ if pid == 0 {
+ path = fmt.Sprintf("%s/net/%s", root, t.filename)
+ } else {
+ path = fmt.Sprintf("%s/%d/net/%s", root, pid, t.filename)
+ }
+ switch t.family {
+ case syscall.AF_INET, syscall.AF_INET6:
+ ls, err = processInet(path, t, inodes, pid)
+ case syscall.AF_UNIX:
+ ls, err = processUnix(path, t, inodes, pid)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ls {
+ // Build TCP key to id the connection uniquely
+ // socket type, src ip, src port, dst ip, dst port and state should be enough
+ // to prevent duplications.
+ connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
+ if _, ok := dupCheckMap[connKey]; ok {
+ continue
+ }
+
+ conn := ConnectionStat{
+ Fd: c.fd,
+ Family: c.family,
+ Type: c.sockType,
+ Laddr: c.laddr,
+ Raddr: c.raddr,
+ Status: c.status,
+ Pid: c.pid,
+ }
+ if c.pid == 0 {
+ conn.Pid = c.boundPid
+ } else {
+ conn.Pid = c.pid
+ }
+
+ if !skipUids {
+ // fetch process owner Real, effective, saved set, and filesystem UIDs
+ proc := process{Pid: conn.Pid}
+ conn.Uids, _ = proc.getUids(ctx)
+ }
+
+ ret = append(ret, conn)
+ dupCheckMap[connKey] = struct{}{}
+ }
+
+ }
+
+ return ret, nil
+}
+
+// getProcInodes returns fd of the pid.
+func getProcInodes(root string, pid int32, maxConn int) (map[string][]inodeMap, error) {
+ ret := make(map[string][]inodeMap)
+
+ dir := fmt.Sprintf("%s/%d/fd", root, pid)
+ f, err := os.Open(dir)
+ if err != nil {
+ return ret, err
+ }
+ defer f.Close()
+ dirEntries, err := f.ReadDir(maxConn)
+ if err != nil {
+ return ret, err
+ }
+ for _, dirEntry := range dirEntries {
+ inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, dirEntry.Name())
+
+ inode, err := os.Readlink(inodePath)
+ if err != nil {
+ continue
+ }
+ if !strings.HasPrefix(inode, "socket:[") {
+ continue
+ }
+ // the process is using a socket
+ l := len(inode)
+ inode = inode[8 : l-1]
+ _, ok := ret[inode]
+ if !ok {
+ ret[inode] = make([]inodeMap, 0)
+ }
+ fd, err := strconv.ParseInt(dirEntry.Name(), 10, 32)
+ if err != nil {
+ continue
+ }
+
+ i := inodeMap{
+ pid: pid,
+ fd: uint32(fd),
+ }
+ ret[inode] = append(ret[inode], i)
+ }
+ return ret, nil
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+
+ d, err := os.Open(common.HostProcWithContext(ctx))
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ fnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, fname := range fnames {
+ pid, err := strconv.ParseInt(fname, 10, 32)
+ if err != nil {
+ // if not numeric name, just skip
+ continue
+ }
+ ret = append(ret, int32(pid))
+ }
+
+ return ret, nil
+}
+
+// Note: the following is based off process_linux structs and methods
+// we need these to fetch the owner of a process ID
+// FIXME: Import process occures import cycle.
+// see remarks on pids()
+type process struct {
+ Pid int32 `json:"pid"`
+ uids []int32
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *process) getUids(ctx context.Context) ([]int32, error) {
+ err := p.fillFromStatus(ctx)
+ if err != nil {
+ return []int32{}, err
+ }
+ return p.uids, nil
+}
+
+// Get status from /proc/(pid)/status
+func (p *process) fillFromStatus(ctx context.Context) error {
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
+ contents, err := os.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(contents), "\n")
+ for _, line := range lines {
+ tabParts := strings.SplitN(line, "\t", 2)
+ if len(tabParts) < 2 {
+ continue
+ }
+ value := tabParts[1]
+ switch strings.TrimRight(tabParts[0], ":") {
+ case "Uid":
+ p.uids = make([]int32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.uids = append(p.uids, int32(v))
+ }
+ }
+ }
+ return nil
+}
+
+func getProcInodesAllWithContext(ctx context.Context, root string, maxConn int) (map[string][]inodeMap, error) {
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ ret := make(map[string][]inodeMap)
+
+ for _, pid := range pids {
+ t, err := getProcInodes(root, pid, maxConn)
+ if err != nil {
+ // skip if permission error or no longer exists
+ if os.IsPermission(err) || os.IsNotExist(err) || errors.Is(err, io.EOF) {
+ continue
+ }
+ return ret, err
+ }
+ if len(t) == 0 {
+ continue
+ }
+ // TODO: update ret.
+ ret = updateMap(ret, t)
+ }
+ return ret, nil
+}
+
+// decodeAddress decode addresse represents addr in proc/net/*
+// ex:
+// "0500000A:0016" -> "10.0.0.5", 22
+// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
+func decodeAddress(family uint32, src string) (Addr, error) {
+ t := strings.Split(src, ":")
+ if len(t) != 2 {
+ return Addr{}, fmt.Errorf("does not contain port, %s", src)
+ }
+ addr := t[0]
+ port, err := strconv.ParseUint(t[1], 16, 16)
+ if err != nil {
+ return Addr{}, fmt.Errorf("invalid port, %s", src)
+ }
+ decoded, err := hex.DecodeString(addr)
+ if err != nil {
+ return Addr{}, fmt.Errorf("decode error, %w", err)
+ }
+ var ip net.IP
+
+ if family == syscall.AF_INET {
+ if common.IsLittleEndian() {
+ ip = net.IP(Reverse(decoded))
+ } else {
+ ip = net.IP(decoded)
+ }
+ } else { // IPv6
+ ip, err = parseIPv6HexString(decoded)
+ if err != nil {
+ return Addr{}, err
+ }
+ }
+ return Addr{
+ IP: ip.String(),
+ Port: uint32(port),
+ }, nil
+}
+
+func Reverse(s []byte) []byte {
+ for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
+ s[i], s[j] = s[j], s[i]
+ }
+ return s
+}
+
+// parseIPv6HexString parse array of bytes to IPv6 string
+func parseIPv6HexString(src []byte) (net.IP, error) {
+ if len(src) != 16 {
+ return nil, errors.New("invalid IPv6 string")
+ }
+
+ buf := make([]byte, 0, 16)
+ for i := 0; i < len(src); i += 4 {
+ r := Reverse(src[i : i+4])
+ buf = append(buf, r...)
+ }
+ return net.IP(buf), nil
+}
+
+func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+ if strings.HasSuffix(file, "6") && !common.PathExists(file) {
+ // IPv6 not supported, return empty.
+ return []connTmp{}, nil
+ }
+
+ // Read the contents of the /proc file with a single read sys call.
+ // This minimizes duplicates in the returned connections
+ // For more info:
+ // https://github.com/shirou/gopsutil/pull/361
+ contents, err := os.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+
+ lines := bytes.Split(contents, []byte("\n"))
+
+ var ret []connTmp
+ // skip first line
+ for _, line := range lines[1:] {
+ l := strings.Fields(string(line))
+ if len(l) < 10 {
+ continue
+ }
+ laddr := l[1]
+ raddr := l[2]
+ status := l[3]
+ inode := l[9]
+ pid := int32(0)
+ fd := uint32(0)
+ i, exists := inodes[inode]
+ if exists {
+ pid = i[0].pid
+ fd = i[0].fd
+ }
+ if filterPid > 0 && filterPid != pid {
+ continue
+ }
+ if kind.sockType == syscall.SOCK_STREAM {
+ status = tcpStatuses[status]
+ } else {
+ status = "NONE"
+ }
+ la, err := decodeAddress(kind.family, laddr)
+ if err != nil {
+ continue
+ }
+ ra, err := decodeAddress(kind.family, raddr)
+ if err != nil {
+ continue
+ }
+
+ ret = append(ret, connTmp{
+ fd: fd,
+ family: kind.family,
+ sockType: kind.sockType,
+ laddr: la,
+ raddr: ra,
+ status: status,
+ pid: pid,
+ })
+ }
+
+ return ret, nil
+}
+
+func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+ // Read the contents of the /proc file with a single read sys call.
+ // This minimizes duplicates in the returned connections
+ // For more info:
+ // https://github.com/shirou/gopsutil/pull/361
+ contents, err := os.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+
+ lines := bytes.Split(contents, []byte("\n"))
+
+ var ret []connTmp
+ // skip first line
+ for _, line := range lines[1:] {
+ tokens := strings.Fields(string(line))
+ if len(tokens) < 6 {
+ continue
+ }
+ st, err := strconv.ParseInt(tokens[4], 10, 32)
+ if err != nil {
+ return nil, err
+ }
+
+ inode := tokens[6]
+
+ var pairs []inodeMap
+ pairs, exists := inodes[inode]
+ if !exists {
+ pairs = []inodeMap{
+ {},
+ }
+ }
+ for _, pair := range pairs {
+ if filterPid > 0 && filterPid != pair.pid {
+ continue
+ }
+ var path string
+ if len(tokens) == 8 {
+ path = tokens[len(tokens)-1]
+ }
+ ret = append(ret, connTmp{
+ fd: pair.fd,
+ family: kind.family,
+ sockType: uint32(st),
+ laddr: Addr{
+ IP: path,
+ },
+ pid: pair.pid,
+ status: "NONE",
+ path: path,
+ })
+ }
+ }
+
+ return ret, nil
+}
+
+func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
+ for key, value := range add {
+ a, exists := src[key]
+ if !exists {
+ src[key] = value
+ continue
+ }
+ src[key] = append(a, value...)
+ }
+ return src
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go
new file mode 100644
index 0000000..a90d590
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+func ParseNetstat(output string, mode string,
+ iocs map[string]IOCountersStat,
+) error {
+ lines := strings.Split(output, "\n")
+
+ exists := make([]string, 0, len(lines)-1)
+
+ columns := 9
+ if mode == "inb" {
+ columns = 6
+ }
+ for _, line := range lines {
+ values := strings.Fields(line)
+ if len(values) < 1 || values[0] == "Name" {
+ continue
+ }
+ if common.StringsHas(exists, values[0]) {
+ // skip if already get
+ continue
+ }
+
+ if len(values) < columns {
+ continue
+ }
+ base := 1
+ // sometimes Address is omitted
+ if len(values) < columns {
+ base = 0
+ }
+
+ parsed := make([]uint64, 0, 8)
+ var vv []string
+ switch mode {
+ case "inb":
+ vv = []string{
+ values[base+3], // BytesRecv
+ values[base+4], // BytesSent
+ }
+ case "ind":
+ vv = []string{
+ values[base+3], // Ipkts
+ values[base+4], // Idrop
+ values[base+5], // Opkts
+ values[base+6], // Odrops
+ }
+ case "ine":
+ vv = []string{
+ values[base+4], // Ierrs
+ values[base+6], // Oerrs
+ }
+ }
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ t, err := strconv.ParseUint(target, 10, 64)
+ if err != nil {
+ return err
+ }
+ parsed = append(parsed, t)
+ }
+ exists = append(exists, values[0])
+
+ n, present := iocs[values[0]]
+ if !present {
+ n = IOCountersStat{Name: values[0]}
+ }
+
+ switch mode {
+ case "inb":
+ n.BytesRecv = parsed[0]
+ n.BytesSent = parsed[1]
+ case "ind":
+ n.PacketsRecv = parsed[0]
+ n.Dropin = parsed[1]
+ n.PacketsSent = parsed[2]
+ n.Dropout = parsed[3]
+ case "ine":
+ n.Errin = parsed[0]
+ n.Errout = parsed[1]
+ }
+
+ iocs[n.Name] = n
+ }
+ return nil
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ netstat, err := exec.LookPath("netstat")
+ if err != nil {
+ return nil, err
+ }
+ out, err := invoke.CommandWithContext(ctx, netstat, "-inb")
+ if err != nil {
+ return nil, err
+ }
+ out2, err := invoke.CommandWithContext(ctx, netstat, "-ind")
+ if err != nil {
+ return nil, err
+ }
+ out3, err := invoke.CommandWithContext(ctx, netstat, "-ine")
+ if err != nil {
+ return nil, err
+ }
+ iocs := make(map[string]IOCountersStat)
+
+ lines := strings.Split(string(out), "\n")
+ ret := make([]IOCountersStat, 0, len(lines)-1)
+
+ err = ParseNetstat(string(out), "inb", iocs)
+ if err != nil {
+ return nil, err
+ }
+ err = ParseNetstat(string(out2), "ind", iocs)
+ if err != nil {
+ return nil, err
+ }
+ err = ParseNetstat(string(out3), "ine", iocs)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ioc := range iocs {
+ ret = append(ret, ioc)
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func parseNetstatLine(line string) (ConnectionStat, error) {
+ f := strings.Fields(line)
+ if len(f) < 5 {
+ return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+ }
+
+ var netType, netFamily uint32
+ switch f[0] {
+ case "tcp":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET
+ case "udp":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET
+ case "tcp6":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET6
+ case "udp6":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET6
+ default:
+ return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+ }
+
+ laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+ }
+
+ n := ConnectionStat{
+ Fd: uint32(0), // not supported
+ Family: uint32(netFamily),
+ Type: uint32(netType),
+ Laddr: laddr,
+ Raddr: raddr,
+ Pid: int32(0), // not supported
+ }
+ if len(f) == 6 {
+ n.Status = f[5]
+ }
+
+ return n, nil
+}
+
+func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
+ parse := func(l string) (Addr, error) {
+ matches := portMatch.FindStringSubmatch(l)
+ if matches == nil {
+ return Addr{}, fmt.Errorf("wrong addr, %s", l)
+ }
+ host := matches[1]
+ port := matches[2]
+ if host == "*" {
+ switch family {
+ case syscall.AF_INET:
+ host = "0.0.0.0"
+ case syscall.AF_INET6:
+ host = "::"
+ default:
+ return Addr{}, fmt.Errorf("unknown family, %d", family)
+ }
+ }
+ lport, err := strconv.ParseInt(port, 10, 32)
+ if err != nil {
+ return Addr{}, err
+ }
+ return Addr{IP: host, Port: uint32(lport)}, nil
+ }
+
+ laddr, err = parse(local)
+ if remote != "*.*" { // remote addr exists
+ raddr, err = parse(remote)
+ if err != nil {
+ return laddr, raddr, err
+ }
+ }
+
+ return laddr, raddr, err
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ var ret []ConnectionStat
+
+ args := []string{"-na"}
+ switch strings.ToLower(kind) {
+ default:
+ fallthrough
+ case "":
+ fallthrough
+ case "all":
+ fallthrough
+ case "inet":
+ // nothing to add
+ case "inet4":
+ args = append(args, "-finet")
+ case "inet6":
+ args = append(args, "-finet6")
+ case "tcp":
+ args = append(args, "-ptcp")
+ case "tcp4":
+ args = append(args, "-ptcp", "-finet")
+ case "tcp6":
+ args = append(args, "-ptcp", "-finet6")
+ case "udp":
+ args = append(args, "-pudp")
+ case "udp4":
+ args = append(args, "-pudp", "-finet")
+ case "udp6":
+ args = append(args, "-pudp", "-finet6")
+ case "unix":
+ return ret, common.ErrNotImplementedError
+ }
+
+ netstat, err := exec.LookPath("netstat")
+ if err != nil {
+ return nil, err
+ }
+ out, err := invoke.CommandWithContext(ctx, netstat, args...)
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(out), "\n")
+ for _, line := range lines {
+ if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) {
+ continue
+ }
+ n, err := parseNetstatLine(line)
+ if err != nil {
+ continue
+ }
+
+ ret = append(ret, n)
+ }
+
+ return ret, nil
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go b/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go
new file mode 100644
index 0000000..83eb1d0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build solaris
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var kstatSplit = regexp.MustCompile(`[:\s]+`)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ // collect all the net class's links with below statistics
+ filterstr := "/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/"
+ if runtime.GOOS == "illumos" {
+ filterstr = "/[^vnic]/::mac:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/"
+ }
+ kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-c", "net", "-p", filterstr)
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute kstat: %w", err)
+ }
+
+ lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n")
+ if len(lines) == 0 {
+ return nil, fmt.Errorf("no interface found")
+ }
+ rbytes64arr := make(map[string]uint64)
+ ipackets64arr := make(map[string]uint64)
+ idrops64arr := make(map[string]uint64)
+ ierrorsarr := make(map[string]uint64)
+ obytes64arr := make(map[string]uint64)
+ opackets64arr := make(map[string]uint64)
+ odrops64arr := make(map[string]uint64)
+ oerrorsarr := make(map[string]uint64)
+
+ for _, line := range lines {
+ fields := kstatSplit.Split(line, -1)
+ interfaceName := fields[0]
+ instance := fields[1]
+ switch fields[3] {
+ case "rbytes64":
+ rbytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse rbytes64: %w", err)
+ }
+ case "ipackets64":
+ ipackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse ipackets64: %w", err)
+ }
+ case "idrops64":
+ idrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse idrops64: %w", err)
+ }
+ case "ierrors":
+ ierrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse ierrors: %w", err)
+ }
+ case "obytes64":
+ obytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse obytes64: %w", err)
+ }
+ case "opackets64":
+ opackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse opackets64: %w", err)
+ }
+ case "odrops64":
+ odrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse odrops64: %w", err)
+ }
+ case "oerrors":
+ oerrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse oerrors: %w", err)
+ }
+ }
+ }
+ ret := make([]IOCountersStat, 0)
+ for k := range rbytes64arr {
+ nic := IOCountersStat{
+ Name: k,
+ BytesRecv: rbytes64arr[k],
+ PacketsRecv: ipackets64arr[k],
+ Errin: ierrorsarr[k],
+ Dropin: idrops64arr[k],
+ BytesSent: obytes64arr[k],
+ PacketsSent: opackets64arr[k],
+ Errout: oerrorsarr[k],
+ Dropout: odrops64arr[k],
+ }
+ ret = append(ret, nic)
+ }
+
+ if !pernic {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go b/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go
new file mode 100644
index 0000000..6eb7e2f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || darwin
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ var ret []ConnectionStat
+
+ args := []string{"-i"}
+ switch strings.ToLower(kind) {
+ default:
+ fallthrough
+ case "":
+ fallthrough
+ case "all":
+ fallthrough
+ case "inet":
+ args = append(args, "tcp", "-i", "udp")
+ case "inet4":
+ args = append(args, "4")
+ case "inet6":
+ args = append(args, "6")
+ case "tcp":
+ args = append(args, "tcp")
+ case "tcp4":
+ args = append(args, "4tcp")
+ case "tcp6":
+ args = append(args, "6tcp")
+ case "udp":
+ args = append(args, "udp")
+ case "udp4":
+ args = append(args, "4udp")
+ case "udp6":
+ args = append(args, "6udp")
+ case "unix":
+ args = []string{"-U"}
+ }
+
+ r, err := common.CallLsofWithContext(ctx, invoke, pid, args...)
+ if err != nil {
+ return nil, err
+ }
+ for _, rr := range r {
+ if strings.HasPrefix(rr, "COMMAND") {
+ continue
+ }
+ n, err := parseNetLine(rr)
+ if err != nil {
+ continue
+ }
+
+ ret = append(ret, n)
+ }
+
+ return ret, nil
+}
+
+var constMap = map[string]int{
+ "unix": syscall.AF_UNIX,
+ "TCP": syscall.SOCK_STREAM,
+ "UDP": syscall.SOCK_DGRAM,
+ "IPv4": syscall.AF_INET,
+ "IPv6": syscall.AF_INET6,
+}
+
+func parseNetLine(line string) (ConnectionStat, error) {
+ f := strings.Fields(line)
+ if len(f) < 8 {
+ return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+ }
+
+ if len(f) == 8 {
+ f = append(f, f[7])
+ f[7] = "unix"
+ }
+
+ pid, err := strconv.ParseInt(f[1], 10, 32)
+ if err != nil {
+ return ConnectionStat{}, err
+ }
+ fd, err := strconv.ParseInt(strings.Trim(f[3], "u"), 10, 32)
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
+ }
+ netFamily, ok := constMap[f[4]]
+ if !ok {
+ return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
+ }
+ netType, ok := constMap[f[7]]
+ if !ok {
+ return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
+ }
+
+ var laddr, raddr Addr
+ if f[7] == "unix" {
+ laddr.IP = f[8]
+ } else {
+ laddr, raddr, err = parseNetAddr(f[8])
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
+ }
+ }
+
+ n := ConnectionStat{
+ Fd: uint32(fd),
+ Family: uint32(netFamily),
+ Type: uint32(netType),
+ Laddr: laddr,
+ Raddr: raddr,
+ Pid: int32(pid),
+ }
+ if len(f) == 10 {
+ n.Status = strings.Trim(f[9], "()")
+ }
+
+ return n, nil
+}
+
+func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) {
+ parse := func(l string) (Addr, error) {
+ host, port, err := net.SplitHostPort(l)
+ if err != nil {
+ return Addr{}, fmt.Errorf("wrong addr, %s", l)
+ }
+ lport, err := strconv.ParseInt(port, 10, 32)
+ if err != nil {
+ return Addr{}, err
+ }
+ return Addr{IP: host, Port: uint32(lport)}, nil
+ }
+
+ addrs := strings.Split(line, "->")
+ if len(addrs) == 0 {
+ return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line)
+ }
+ laddr, err = parse(addrs[0])
+ if len(addrs) == 2 { // remote addr exists
+ raddr, err = parse(addrs[1])
+ if err != nil {
+ return laddr, raddr, err
+ }
+ }
+
+ return laddr, raddr, err
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go b/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go
new file mode 100644
index 0000000..00ebf89
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go
@@ -0,0 +1,729 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package net
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
+ procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable")
+ procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable")
+ procGetIfEntry2 = modiphlpapi.NewProc("GetIfEntry2")
+)
+
+const (
+ TCPTableBasicListener = iota
+ TCPTableBasicConnections
+ TCPTableBasicAll
+ TCPTableOwnerPIDListener
+ TCPTableOwnerPIDConnections
+ TCPTableOwnerPIDAll
+ TCPTableOwnerModuleListener
+ TCPTableOwnerModuleConnections
+ TCPTableOwnerModuleAll
+)
+
+type netConnectionKindType struct {
+ family uint32
+ sockType uint32
+ filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp",
+}
+
+var kindTCP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp6",
+}
+
+var kindUDP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp",
+}
+
+var kindUDP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp6",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "tcp": {kindTCP4, kindTCP6},
+ "tcp4": {kindTCP4},
+ "tcp6": {kindTCP6},
+ "udp": {kindUDP4, kindUDP6},
+ "udp4": {kindUDP4},
+ "udp6": {kindUDP6},
+ "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "inet4": {kindTCP4, kindUDP4},
+ "inet6": {kindTCP6, kindUDP6},
+}
+
+// https://github.com/microsoft/ethr/blob/aecdaf923970e5a9b4c461b4e2e3963d781ad2cc/plt_windows.go#L114-L170
+type guid struct {
+ Data1 uint32
+ Data2 uint16
+ Data3 uint16
+ Data4 [8]byte
+}
+
+const (
+ maxStringSize = 256
+ maxPhysAddressLength = 32
+ pad0for64_4for32 = 0
+)
+
+type mibIfRow2 struct {
+ InterfaceLuid uint64
+ InterfaceIndex uint32
+ InterfaceGuid guid
+ Alias [maxStringSize + 1]uint16
+ Description [maxStringSize + 1]uint16
+ PhysicalAddressLength uint32
+ PhysicalAddress [maxPhysAddressLength]uint8
+ PermanentPhysicalAddress [maxPhysAddressLength]uint8
+ Mtu uint32
+ Type uint32
+ TunnelType uint32
+ MediaType uint32
+ PhysicalMediumType uint32
+ AccessType uint32
+ DirectionType uint32
+ InterfaceAndOperStatusFlags uint32
+ OperStatus uint32
+ AdminStatus uint32
+ MediaConnectState uint32
+ NetworkGuid guid
+ ConnectionType uint32
+ padding1 [pad0for64_4for32]byte
+ TransmitLinkSpeed uint64
+ ReceiveLinkSpeed uint64
+ InOctets uint64
+ InUcastPkts uint64
+ InNUcastPkts uint64
+ InDiscards uint64
+ InErrors uint64
+ InUnknownProtos uint64
+ InUcastOctets uint64
+ InMulticastOctets uint64
+ InBroadcastOctets uint64
+ OutOctets uint64
+ OutUcastPkts uint64
+ OutNUcastPkts uint64
+ OutDiscards uint64
+ OutErrors uint64
+ OutUcastOctets uint64
+ OutMulticastOctets uint64
+ OutBroadcastOctets uint64
+ OutQLen uint64
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ ifs, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ var counters []IOCountersStat
+
+ err = procGetIfEntry2.Find()
+ if err == nil { // Vista+, uint64 values (issue#693)
+ for _, ifi := range ifs {
+ c := IOCountersStat{
+ Name: ifi.Name,
+ }
+
+ row := mibIfRow2{InterfaceIndex: uint32(ifi.Index)}
+ ret, _, err := procGetIfEntry2.Call(uintptr(unsafe.Pointer(&row)))
+ if ret != 0 {
+ return nil, os.NewSyscallError("GetIfEntry2", err)
+ }
+ c.BytesSent = uint64(row.OutOctets)
+ c.BytesRecv = uint64(row.InOctets)
+ c.PacketsSent = uint64(row.OutUcastPkts)
+ c.PacketsRecv = uint64(row.InUcastPkts)
+ c.Errin = uint64(row.InErrors)
+ c.Errout = uint64(row.OutErrors)
+ c.Dropin = uint64(row.InDiscards)
+ c.Dropout = uint64(row.OutDiscards)
+
+ counters = append(counters, c)
+ }
+ } else { // WinXP fallback, uint32 values
+ for _, ifi := range ifs {
+ c := IOCountersStat{
+ Name: ifi.Name,
+ }
+
+ row := windows.MibIfRow{Index: uint32(ifi.Index)}
+ err = windows.GetIfEntry(&row)
+ if err != nil {
+ return nil, os.NewSyscallError("GetIfEntry", err)
+ }
+ c.BytesSent = uint64(row.OutOctets)
+ c.BytesRecv = uint64(row.InOctets)
+ c.PacketsSent = uint64(row.OutUcastPkts)
+ c.PacketsRecv = uint64(row.InUcastPkts)
+ c.Errin = uint64(row.InErrors)
+ c.Errout = uint64(row.OutErrors)
+ c.Dropin = uint64(row.InDiscards)
+ c.Dropout = uint64(row.OutDiscards)
+
+ counters = append(counters, c)
+ }
+ }
+
+ if !pernic {
+ return getIOCountersAll(counters)
+ }
+ return counters, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ tmap, ok := netConnectionKindMap[kind]
+ if !ok {
+ return nil, fmt.Errorf("invalid kind, %s", kind)
+ }
+ return getProcInet(tmap, pid)
+}
+
+func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) {
+ stats := make([]ConnectionStat, 0)
+
+ for _, kind := range kinds {
+ s, err := getNetStatWithKind(kind)
+ if err != nil {
+ continue
+ }
+
+ if pid == 0 {
+ stats = append(stats, s...)
+ } else {
+ for _, ns := range s {
+ if ns.Pid != pid {
+ continue
+ }
+ stats = append(stats, ns)
+ }
+ }
+ }
+
+ return stats, nil
+}
+
+func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) {
+ if kindType.filename == "" {
+ return nil, fmt.Errorf("kind filename must be required")
+ }
+
+ switch kindType.filename {
+ case kindTCP4.filename:
+ return getTCPConnections(kindTCP4.family)
+ case kindTCP6.filename:
+ return getTCPConnections(kindTCP6.family)
+ case kindUDP4.filename:
+ return getUDPConnections(kindUDP4.family)
+ case kindUDP6.filename:
+ return getUDPConnections(kindUDP6.family)
+ }
+
+ return nil, fmt.Errorf("invalid kind filename, %s", kindType.filename)
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+ return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func getTableUintptr(family uint32, buf []byte) uintptr {
+ var (
+ pmibTCPTable pmibTCPTableOwnerPidAll
+ pmibTCP6Table pmibTCP6TableOwnerPidAll
+
+ p uintptr
+ )
+ switch family {
+ case kindTCP4.family:
+ if len(buf) > 0 {
+ pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ }
+ case kindTCP6.family:
+ if len(buf) > 0 {
+ pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ }
+ }
+ return p
+}
+
+func getTableInfo(filename string, table interface{}) (index, step, length int) {
+ switch filename {
+ case kindTCP4.filename:
+ index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table))
+ length = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries)
+ case kindTCP6.filename:
+ index = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table))
+ length = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)
+ case kindUDP4.filename:
+ index = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table))
+ length = int(table.(pmibUDPTableOwnerPid).DwNumEntries)
+ case kindUDP6.filename:
+ index = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table))
+ length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries)
+ }
+
+ return
+}
+
+func getTCPConnections(family uint32) ([]ConnectionStat, error) {
+ var (
+ p uintptr
+ buf []byte
+ size uint32
+
+ pmibTCPTable pmibTCPTableOwnerPidAll
+ pmibTCP6Table pmibTCP6TableOwnerPidAll
+ )
+
+ if family == 0 {
+ return nil, fmt.Errorf("faimly must be required")
+ }
+
+ for {
+ switch family {
+ case kindTCP4.family:
+ if len(buf) > 0 {
+ pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ }
+ case kindTCP6.family:
+ if len(buf) > 0 {
+ pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ }
+ }
+
+ err := getExtendedTcpTable(p,
+ &size,
+ true,
+ family,
+ tcpTableOwnerPidAll,
+ 0)
+ if err == nil {
+ break
+ }
+ if err != windows.ERROR_INSUFFICIENT_BUFFER {
+ return nil, err
+ }
+ buf = make([]byte, size)
+ }
+
+ var (
+ index, step int
+ length int
+ )
+
+ stats := make([]ConnectionStat, 0)
+ switch family {
+ case kindTCP4.family:
+ index, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable)
+ case kindTCP6.family:
+ index, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table)
+ }
+
+ if length == 0 {
+ return nil, nil
+ }
+
+ for i := 0; i < length; i++ {
+ switch family {
+ case kindTCP4.family:
+ mibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ case kindTCP6.family:
+ mibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ }
+
+ index += step
+ }
+ return stats, nil
+}
+
+func getUDPConnections(family uint32) ([]ConnectionStat, error) {
+ var (
+ p uintptr
+ buf []byte
+ size uint32
+
+ pmibUDPTable pmibUDPTableOwnerPid
+ pmibUDP6Table pmibUDP6TableOwnerPid
+ )
+
+ if family == 0 {
+ return nil, fmt.Errorf("faimly must be required")
+ }
+
+ for {
+ switch family {
+ case kindUDP4.family:
+ if len(buf) > 0 {
+ pmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibUDPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibUDPTable))
+ }
+ case kindUDP6.family:
+ if len(buf) > 0 {
+ pmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibUDP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibUDP6Table))
+ }
+ }
+
+ err := getExtendedUdpTable(
+ p,
+ &size,
+ true,
+ family,
+ udpTableOwnerPid,
+ 0,
+ )
+ if err == nil {
+ break
+ }
+ if err != windows.ERROR_INSUFFICIENT_BUFFER {
+ return nil, err
+ }
+ buf = make([]byte, size)
+ }
+
+ var index, step, length int
+
+ stats := make([]ConnectionStat, 0)
+ switch family {
+ case kindUDP4.family:
+ index, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable)
+ case kindUDP6.family:
+ index, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table)
+ }
+
+ if length == 0 {
+ return nil, nil
+ }
+
+ for i := 0; i < length; i++ {
+ switch family {
+ case kindUDP4.family:
+ mibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ case kindUDP6.family:
+ mibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ }
+
+ index += step
+ }
+ return stats, nil
+}
+
+// tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx
+var tcpStatuses = map[mibTCPState]string{
+ 1: "CLOSED",
+ 2: "LISTEN",
+ 3: "SYN_SENT",
+ 4: "SYN_RECEIVED",
+ 5: "ESTABLISHED",
+ 6: "FIN_WAIT_1",
+ 7: "FIN_WAIT_2",
+ 8: "CLOSE_WAIT",
+ 9: "CLOSING",
+ 10: "LAST_ACK",
+ 11: "TIME_WAIT",
+ 12: "DELETE",
+}
+
+func getExtendedTcpTable(pTcpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) {
+ r1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTcpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+ if r1 != 0 {
+ errcode = syscall.Errno(r1)
+ }
+ return
+}
+
+func getExtendedUdpTable(pUdpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) {
+ r1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUdpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+ if r1 != 0 {
+ errcode = syscall.Errno(r1)
+ }
+ return
+}
+
+func getUintptrFromBool(b bool) uintptr {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+const anySize = 1
+
+// type MIB_TCP_STATE int32
+type mibTCPState int32
+
+type tcpTableClass int32
+
+const (
+ tcpTableBasicListener tcpTableClass = iota
+ tcpTableBasicConnections
+ tcpTableBasicAll
+ tcpTableOwnerPidListener
+ tcpTableOwnerPidConnections
+ tcpTableOwnerPidAll
+ tcpTableOwnerModuleListener
+ tcpTableOwnerModuleConnections
+ tcpTableOwnerModuleAll
+)
+
+type udpTableClass int32
+
+const (
+ udpTableBasic udpTableClass = iota
+ udpTableOwnerPid
+ udpTableOwnerModule
+)
+
+// TCP
+
+type mibTCPRowOwnerPid struct {
+ DwState uint32
+ DwLocalAddr uint32
+ DwLocalPort uint32
+ DwRemoteAddr uint32
+ DwRemotePort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindTCP4.family,
+ Type: kindTCP4.sockType,
+ Laddr: Addr{
+ IP: parseIPv4HexString(m.DwLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Raddr: Addr{
+ IP: parseIPv4HexString(m.DwRemoteAddr),
+ Port: uint32(decodePort(m.DwRemotePort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ Status: tcpStatuses[mibTCPState(m.DwState)],
+ }
+
+ return ns
+}
+
+type mibTCPTableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibTCPRowOwnerPid
+}
+
+type mibTCP6RowOwnerPid struct {
+ UcLocalAddr [16]byte
+ DwLocalScopeId uint32
+ DwLocalPort uint32
+ UcRemoteAddr [16]byte
+ DwRemoteScopeId uint32
+ DwRemotePort uint32
+ DwState uint32
+ DwOwningPid uint32
+}
+
+func (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindTCP6.family,
+ Type: kindTCP6.sockType,
+ Laddr: Addr{
+ IP: parseIPv6HexString(m.UcLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Raddr: Addr{
+ IP: parseIPv6HexString(m.UcRemoteAddr),
+ Port: uint32(decodePort(m.DwRemotePort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ Status: tcpStatuses[mibTCPState(m.DwState)],
+ }
+
+ return ns
+}
+
+type mibTCP6TableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibTCP6RowOwnerPid
+}
+
+type (
+ pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid
+ pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid
+)
+
+// UDP
+
+type mibUDPRowOwnerPid struct {
+ DwLocalAddr uint32
+ DwLocalPort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindUDP4.family,
+ Type: kindUDP4.sockType,
+ Laddr: Addr{
+ IP: parseIPv4HexString(m.DwLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ }
+
+ return ns
+}
+
+type mibUDPTableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibUDPRowOwnerPid
+}
+
+type mibUDP6RowOwnerPid struct {
+ UcLocalAddr [16]byte
+ DwLocalScopeId uint32
+ DwLocalPort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindUDP6.family,
+ Type: kindUDP6.sockType,
+ Laddr: Addr{
+ IP: parseIPv6HexString(m.UcLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ }
+
+ return ns
+}
+
+type mibUDP6TableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibUDP6RowOwnerPid
+}
+
+type (
+ pmibUDPTableOwnerPid *mibUDPTableOwnerPid
+ pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid
+)
+
+func decodePort(port uint32) uint16 {
+ return syscall.Ntohs(uint16(port))
+}
+
+func parseIPv4HexString(addr uint32) string {
+ return fmt.Sprintf("%d.%d.%d.%d", addr&255, addr>>8&255, addr>>16&255, addr>>24&255)
+}
+
+func parseIPv6HexString(addr [16]byte) string {
+ var ret [16]byte
+ for i := 0; i < 16; i++ {
+ ret[i] = uint8(addr[i])
+ }
+
+ // convert []byte to net.IP
+ ip := net.IP(ret[:])
+ return ip.String()
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process.go b/vendor/github.com/shirou/gopsutil/v4/process/process.go
new file mode 100644
index 0000000..70411c6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process.go
@@ -0,0 +1,640 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package process
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "runtime"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/mem"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+var (
+ invoke common.Invoker = common.Invoke{}
+ ErrorNoChildren = errors.New("process does not have children") // Deprecated: ErrorNoChildren is never returned by process.Children(), check its returned []*Process slice length instead
+ ErrorProcessNotRunning = errors.New("process does not exist")
+ ErrorNotPermitted = errors.New("operation not permitted")
+)
+
+type Process struct {
+ Pid int32 `json:"pid"`
+ name string
+ status string
+ parent int32
+ parentMutex sync.RWMutex // for windows ppid cache
+ numCtxSwitches *NumCtxSwitchesStat
+ uids []uint32
+ gids []uint32
+ groups []uint32
+ numThreads int32
+ memInfo *MemoryInfoStat
+ sigInfo *SignalInfoStat
+ createTime int64
+
+ lastCPUTimes *cpu.TimesStat
+ lastCPUTime time.Time
+
+ tgid int32
+}
+
+// Process status
+const (
+ // Running marks a task a running or runnable (on the run queue)
+ Running = "running"
+ // Blocked marks a task waiting on a short, uninterruptible operation (usually I/O)
+ Blocked = "blocked"
+ // Idle marks a task sleeping for more than about 20 seconds
+ Idle = "idle"
+ // Lock marks a task waiting to acquire a lock
+ Lock = "lock"
+ // Sleep marks task waiting for short, interruptible operation
+ Sleep = "sleep"
+ // Stop marks a stopped process
+ Stop = "stop"
+ // Wait marks an idle interrupt thread (or paging in pre 2.6.xx Linux)
+ Wait = "wait"
+ // Zombie marks a defunct process, terminated but not reaped by its parent
+ Zombie = "zombie"
+
+ // Solaris states. See https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
+ Daemon = "daemon"
+ Detached = "detached"
+ System = "system"
+ Orphan = "orphan"
+
+ UnknownState = ""
+)
+
+type OpenFilesStat struct {
+ Path string `json:"path"`
+ Fd uint64 `json:"fd"`
+}
+
+type MemoryInfoStat struct {
+ RSS uint64 `json:"rss"` // bytes
+ VMS uint64 `json:"vms"` // bytes
+ HWM uint64 `json:"hwm"` // bytes
+ Data uint64 `json:"data"` // bytes
+ Stack uint64 `json:"stack"` // bytes
+ Locked uint64 `json:"locked"` // bytes
+ Swap uint64 `json:"swap"` // bytes
+}
+
+type SignalInfoStat struct {
+ PendingProcess uint64 `json:"pending_process"`
+ PendingThread uint64 `json:"pending_thread"`
+ Blocked uint64 `json:"blocked"`
+ Ignored uint64 `json:"ignored"`
+ Caught uint64 `json:"caught"`
+}
+
+type RlimitStat struct {
+ Resource int32 `json:"resource"`
+ Soft uint64 `json:"soft"`
+ Hard uint64 `json:"hard"`
+ Used uint64 `json:"used"`
+}
+
+type IOCountersStat struct {
+ // ReadCount is a number of read I/O operations such as syscalls.
+ ReadCount uint64 `json:"readCount"`
+ // WriteCount is a number of read I/O operations such as syscalls.
+ WriteCount uint64 `json:"writeCount"`
+ // ReadBytes is a number of all I/O read in bytes. This includes disk I/O on Linux and Windows.
+ ReadBytes uint64 `json:"readBytes"`
+ // WriteBytes is a number of all I/O write in bytes. This includes disk I/O on Linux and Windows.
+ WriteBytes uint64 `json:"writeBytes"`
+ // DiskReadBytes is a number of disk I/O write in bytes. Currently only Linux has this value.
+ DiskReadBytes uint64 `json:"diskReadBytes"`
+ // DiskWriteBytes is a number of disk I/O read in bytes. Currently only Linux has this value.
+ DiskWriteBytes uint64 `json:"diskWriteBytes"`
+}
+
+type NumCtxSwitchesStat struct {
+ Voluntary int64 `json:"voluntary"`
+ Involuntary int64 `json:"involuntary"`
+}
+
+type PageFaultsStat struct {
+ MinorFaults uint64 `json:"minorFaults"`
+ MajorFaults uint64 `json:"majorFaults"`
+ ChildMinorFaults uint64 `json:"childMinorFaults"`
+ ChildMajorFaults uint64 `json:"childMajorFaults"`
+}
+
+// Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
+// from libc6-dev package in Ubuntu 16.10
+const (
+ RLIMIT_CPU int32 = 0
+ RLIMIT_FSIZE int32 = 1
+ RLIMIT_DATA int32 = 2
+ RLIMIT_STACK int32 = 3
+ RLIMIT_CORE int32 = 4
+ RLIMIT_RSS int32 = 5
+ RLIMIT_NPROC int32 = 6
+ RLIMIT_NOFILE int32 = 7
+ RLIMIT_MEMLOCK int32 = 8
+ RLIMIT_AS int32 = 9
+ RLIMIT_LOCKS int32 = 10
+ RLIMIT_SIGPENDING int32 = 11
+ RLIMIT_MSGQUEUE int32 = 12
+ RLIMIT_NICE int32 = 13
+ RLIMIT_RTPRIO int32 = 14
+ RLIMIT_RTTIME int32 = 15
+)
+
+func (p Process) String() string {
+ s, _ := json.Marshal(p)
+ return string(s)
+}
+
+func (o OpenFilesStat) String() string {
+ s, _ := json.Marshal(o)
+ return string(s)
+}
+
+func (m MemoryInfoStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+func (r RlimitStat) String() string {
+ s, _ := json.Marshal(r)
+ return string(s)
+}
+
+func (i IOCountersStat) String() string {
+ s, _ := json.Marshal(i)
+ return string(s)
+}
+
+func (p NumCtxSwitchesStat) String() string {
+ s, _ := json.Marshal(p)
+ return string(s)
+}
+
+var enableBootTimeCache bool
+
+// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
+func EnableBootTimeCache(enable bool) {
+ enableBootTimeCache = enable
+}
+
+// Pids returns a slice of process ID list which are running now.
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ pids, err := pidsWithContext(ctx)
+ sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
+ return pids, err
+}
+
+// Processes returns a slice of pointers to Process structs for all
+// currently running processes.
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+// NewProcess creates a new Process instance, it only stores the pid and
+// checks that the process exists. Other method on Process can be used
+// to get more information about the process. An error will be returned
+// if the process does not exist.
+func NewProcess(pid int32) (*Process, error) {
+ return NewProcessWithContext(context.Background(), pid)
+}
+
+func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
+ p := &Process{
+ Pid: pid,
+ }
+
+ exists, err := PidExistsWithContext(ctx, pid)
+ if err != nil {
+ return p, err
+ }
+ if !exists {
+ return p, ErrorProcessNotRunning
+ }
+ p.CreateTimeWithContext(ctx)
+ return p, nil
+}
+
+func PidExists(pid int32) (bool, error) {
+ return PidExistsWithContext(context.Background(), pid)
+}
+
+// Background returns true if the process is in background, false otherwise.
+func (p *Process) Background() (bool, error) {
+ return p.BackgroundWithContext(context.Background())
+}
+
+func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
+ fg, err := p.ForegroundWithContext(ctx)
+ if err != nil {
+ return false, err
+ }
+ return !fg, err
+}
+
+// If interval is 0, return difference from last call(non-blocking).
+// If interval > 0, wait interval sec and return difference between start and end.
+func (p *Process) Percent(interval time.Duration) (float64, error) {
+ return p.PercentWithContext(context.Background(), interval)
+}
+
+func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
+ cpuTimes, err := p.TimesWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ now := time.Now()
+
+ if interval > 0 {
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ if err := common.Sleep(ctx, interval); err != nil {
+ return 0, err
+ }
+ cpuTimes, err = p.TimesWithContext(ctx)
+ now = time.Now()
+ if err != nil {
+ return 0, err
+ }
+ } else {
+ if p.lastCPUTimes == nil {
+ // invoked first time
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ return 0, nil
+ }
+ }
+
+ numcpu := runtime.NumCPU()
+ delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
+ ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ return ret, nil
+}
+
+// IsRunning returns whether the process is still running or not.
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ createTime, err := p.CreateTimeWithContext(ctx)
+ if err != nil {
+ return false, err
+ }
+ p2, err := NewProcessWithContext(ctx, p.Pid)
+ if errors.Is(err, ErrorProcessNotRunning) {
+ return false, nil
+ }
+ createTime2, err := p2.CreateTimeWithContext(ctx)
+ if err != nil {
+ return false, err
+ }
+ return createTime == createTime2, nil
+}
+
+// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ if p.createTime != 0 {
+ return p.createTime, nil
+ }
+ createTime, err := p.createTimeWithContext(ctx)
+ p.createTime = createTime
+ return p.createTime, err
+}
+
+func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
+ if delta == 0 {
+ return 0
+ }
+ // https://github.com/giampaolo/psutil/blob/c034e6692cf736b5e87d14418a8153bb03f6cf42/psutil/__init__.py#L1064
+ delta_proc := (t2.User - t1.User) + (t2.System - t1.System)
+ if delta_proc <= 0 {
+ return 0
+ }
+ overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
+ return overall_percent
+}
+
+// MemoryPercent returns how many percent of the total RAM this process uses
+func (p *Process) MemoryPercent() (float32, error) {
+ return p.MemoryPercentWithContext(context.Background())
+}
+
+func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
+ machineMemory, err := mem.VirtualMemoryWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ total := machineMemory.Total
+
+ processMemory, err := p.MemoryInfoWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ used := processMemory.RSS
+
+ return (100 * float32(used) / float32(total)), nil
+}
+
+// CPUPercent returns how many percent of the CPU time this process uses
+func (p *Process) CPUPercent() (float64, error) {
+ return p.CPUPercentWithContext(context.Background())
+}
+
+func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
+ crt_time, err := p.createTimeWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+
+ cput, err := p.TimesWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+
+ created := time.Unix(0, crt_time*int64(time.Millisecond))
+ totalTime := time.Since(created).Seconds()
+ if totalTime <= 0 {
+ return 0, nil
+ }
+
+ return 100 * cput.Total() / totalTime, nil
+}
+
+// Groups returns all group IDs(include supplementary groups) of the process as a slice of the int
+func (p *Process) Groups() ([]uint32, error) {
+ return p.GroupsWithContext(context.Background())
+}
+
+// Ppid returns Parent Process ID of the process.
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+// Name returns name of the process.
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+// Exe returns executable path of the process.
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+// Cmdline returns the command line arguments of the process as a string with
+// each argument separated by 0x20 ascii character.
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+// CmdlineSlice returns the command line arguments of the process as a slice with each
+// element being an argument.
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+// Cwd returns current working directory of the process.
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+// Parent returns parent Process of the process.
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+// ParentWithContext returns parent Process of the process.
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ ppid, err := p.PpidWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return NewProcessWithContext(ctx, ppid)
+}
+
+// Status returns the process status.
+// Return value could be one of these.
+// R: Running S: Sleep T: Stop I: Idle
+// Z: Zombie W: Wait L: Lock
+// The character is same within all supported platforms.
+func (p *Process) Status() ([]string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+// Foreground returns true if the process is in foreground, false otherwise.
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *Process) Uids() ([]uint32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+// Gids returns group ids of the process as a slice of the int
+func (p *Process) Gids() ([]uint32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+// Terminal returns a terminal which is associated with the process.
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+// Nice returns a nice value (priority).
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+// IOnice returns process I/O nice value (priority).
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+// Rlimit returns Resource Limits.
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+// RlimitUsage returns Resource Limits.
+// If gatherUsed is true, the currently used value will be gathered and added
+// to the resulting RlimitStat.
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+// IOCounters returns IO Counters.
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+// NumCtxSwitches returns the number of the context switches of the process.
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+// NumFDs returns the number of File Descriptors used by the process.
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+// NumThreads returns the number of threads used by the process.
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+// Times returns CPU times of the process.
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+// CPUAffinity returns CPU affinity of the process.
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+// MemoryInfo returns generic process memory information,
+// such as RSS and VMS.
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+// MemoryInfoEx returns platform-specific process memory information.
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+// PageFaults returns the process's page fault counters.
+func (p *Process) PageFaults() (*PageFaultsStat, error) {
+ return p.PageFaultsWithContext(context.Background())
+}
+
+// Children returns the children of the process represented as a slice
+// of pointers to Process type.
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+// OpenFiles returns a slice of OpenFilesStat opend by the process.
+// OpenFilesStat includes a file path and file descriptor.
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+// Connections returns a slice of net.ConnectionStat used by the process.
+// This returns all kind of the connection. This means TCP, UDP or UNIX.
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+// ConnectionsMax returns a slice of net.ConnectionStat used by the process at most `max`.
+func (p *Process) ConnectionsMax(maxConn int) ([]net.ConnectionStat, error) {
+ return p.ConnectionsMaxWithContext(context.Background(), maxConn)
+}
+
+// MemoryMaps get memory maps from /proc/(pid)/smaps
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+// Tgid returns thread group id of the process.
+func (p *Process) Tgid() (int32, error) {
+ return p.TgidWithContext(context.Background())
+}
+
+// SendSignal sends a unix.Signal to the process.
+func (p *Process) SendSignal(sig Signal) error {
+ return p.SendSignalWithContext(context.Background(), sig)
+}
+
+// Suspend sends SIGSTOP to the process.
+func (p *Process) Suspend() error {
+ return p.SuspendWithContext(context.Background())
+}
+
+// Resume sends SIGCONT to the process.
+func (p *Process) Resume() error {
+ return p.ResumeWithContext(context.Background())
+}
+
+// Terminate sends SIGTERM to the process.
+func (p *Process) Terminate() error {
+ return p.TerminateWithContext(context.Background())
+}
+
+// Kill sends SIGKILL to the process.
+func (p *Process) Kill() error {
+ return p.KillWithContext(context.Background())
+}
+
+// Username returns a username of the process.
+func (p *Process) Username() (string, error) {
+ return p.UsernameWithContext(context.Background())
+}
+
+// Environ returns the environment variables of the process.
+func (p *Process) Environ() ([]string, error) {
+ return p.EnvironWithContext(context.Background())
+}
+
+// convertStatusChar as reported by the ps command across different platforms.
+func convertStatusChar(letter string) string {
+ // Sources
+ // Darwin: http://www.mywebuniversity.com/Man_Pages/Darwin/man_ps.html
+ // FreeBSD: https://www.freebsd.org/cgi/man.cgi?ps
+ // Linux https://man7.org/linux/man-pages/man1/ps.1.html
+ // OpenBSD: https://man.openbsd.org/ps.1#state
+ // Solaris: https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
+ switch letter {
+ case "A":
+ return Daemon
+ case "D", "U":
+ return Blocked
+ case "E":
+ return Detached
+ case "I":
+ return Idle
+ case "L":
+ return Lock
+ case "O":
+ return Orphan
+ case "R":
+ return Running
+ case "S":
+ return Sleep
+ case "T", "t":
+ // "t" is used by Linux to signal stopped by the debugger during tracing
+ return Stop
+ case "W":
+ return Wait
+ case "Y":
+ return System
+ case "Z":
+ return Zombie
+ default:
+ return UnknownState
+ }
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go
new file mode 100644
index 0000000..dcc0561
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin || freebsd || openbsd
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type MemoryInfoExStat struct{}
+
+type MemoryMapsStat struct{}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func parseKinfoProc(buf []byte) (KinfoProc, error) {
+ var k KinfoProc
+ br := bytes.NewReader(buf)
+ err := common.Read(br, binary.LittleEndian, &k)
+ return k, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go
new file mode 100644
index 0000000..33abc10
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+// copied from sys/sysctl.h
+const (
+ CTLKern = 1 // "high kernel": proc, limits
+ KernProc = 14 // struct: process entries
+ KernProcPID = 1 // by process id
+ KernProcProc = 8 // only return procs
+ KernProcAll = 0 // everything
+ KernProcPathname = 12 // path to executable
+)
+
+type _Ctype_struct___0 struct {
+ Pad uint64
+}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+
+ kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
+ if err != nil {
+ return ret, err
+ }
+
+ for _, proc := range kprocs {
+ ret = append(ret, int32(proc.Proc.P_pid))
+ }
+
+ return ret, nil
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Eproc.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ name := common.ByteToString(k.Proc.P_comm[:])
+
+ if len(name) >= 15 {
+ cmdName, err := p.cmdNameWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ if len(cmdName) > 0 {
+ extendedName := filepath.Base(cmdName)
+ if strings.HasPrefix(extendedName, p.name) {
+ name = extendedName
+ }
+ }
+ }
+
+ return name, nil
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Proc.P_starttime.Sec*1000 + int64(k.Proc.P_starttime.Usec)/1000, nil
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ r, err := callPsWithContext(ctx, "state", p.Pid, false, false)
+ if err != nil {
+ return []string{""}, err
+ }
+ status := convertStatusChar(r[0][0][0:1])
+ return []string{status}, err
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ // See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
+ userEffectiveUID := uint32(k.Eproc.Ucred.Uid)
+
+ return []uint32{userEffectiveUID}, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]uint32, 0, 3)
+ gids = append(gids, uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Pcred.P_svgid))
+
+ return gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+ // k, err := p.getKProc()
+ // if err != nil {
+ // return nil, err
+ // }
+
+ // groups := make([]int32, k.Eproc.Ucred.Ngroups)
+ // for i := int16(0); i < k.Eproc.Ucred.Ngroups; i++ {
+ // groups[i] = int32(k.Eproc.Ucred.Groups[i])
+ // }
+
+ // return groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+ /*
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Eproc.Tdev)
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+ */
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Proc.P_nice), nil
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return nil, nil
+ }
+ ret := make([]*Process, 0, len(procs))
+ for _, proc := range procs {
+ ppid, err := proc.PpidWithContext(ctx)
+ if err != nil {
+ continue
+ }
+ if ppid == p.Pid {
+ ret = append(ret, proc)
+ }
+ }
+ sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+ return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, err
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcessWithContext(ctx, pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+// Returns a proc as defined here:
+// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
+func (p *Process) getKProc() (*unix.KinfoProc, error) {
+ return unix.SysctlKinfoProc("kern.proc.pid", int(p.Pid))
+}
+
+// call ps command.
+// Return value deletes Header line(you must not input wrong arg).
+// And splited by Space. Caller have responsibility to manage.
+// If passed arg pid is 0, get information from all process.
+func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption bool, nameOption bool) ([][]string, error) {
+ var cmd []string
+ if pid == 0 { // will get from all processes.
+ cmd = []string{"-ax", "-o", arg}
+ } else if threadOption {
+ cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
+ } else {
+ cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))}
+ }
+ if nameOption {
+ cmd = append(cmd, "-c")
+ }
+ out, err := invoke.CommandWithContext(ctx, "ps", cmd...)
+ if err != nil {
+ return [][]string{}, err
+ }
+ lines := strings.Split(string(out), "\n")
+
+ var ret [][]string
+ for _, l := range lines[1:] {
+ var lr []string
+ if nameOption {
+ lr = append(lr, l)
+ } else {
+ for _, r := range strings.Split(l, " ") {
+ if r == "" {
+ continue
+ }
+ lr = append(lr, strings.TrimSpace(r))
+ }
+ }
+ if len(lr) != 0 {
+ ret = append(ret, lr)
+ }
+ }
+
+ return ret, nil
+}
+
+var (
+ procPidPath common.ProcPidPathFunc
+ procPidInfo common.ProcPidInfoFunc
+ machTimeBaseInfo common.MachTimeBaseInfoFunc
+)
+
+func registerFuncs() (*common.Library, error) {
+ lib, err := common.NewLibrary(common.System)
+ if err != nil {
+ return nil, err
+ }
+
+ procPidPath = common.GetFunc[common.ProcPidPathFunc](lib, common.ProcPidPathSym)
+ procPidInfo = common.GetFunc[common.ProcPidInfoFunc](lib, common.ProcPidInfoSym)
+ machTimeBaseInfo = common.GetFunc[common.MachTimeBaseInfoFunc](lib, common.MachTimeBaseInfoSym)
+
+ return lib, nil
+}
+
+func getTimeScaleToNanoSeconds() float64 {
+ var timeBaseInfo common.MachTimeBaseInfo
+
+ machTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo)))
+
+ return float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom)
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ lib, err := registerFuncs()
+ if err != nil {
+ return "", err
+ }
+ defer lib.Close()
+
+ buf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE)
+ ret := procPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE)
+
+ if ret <= 0 {
+ return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret)
+ }
+
+ return buf.GoString(), nil
+}
+
+// sys/proc_info.h
+type vnodePathInfo struct {
+ _ [152]byte
+ vipPath [common.MAXPATHLEN]byte
+ _ [1176]byte
+}
+
+// CwdWithContext retrieves the Current Working Directory for the given process.
+// It uses the proc_pidinfo from libproc and will only work for processes the
+// EUID can access. Otherwise "operation not permitted" will be returned as the
+// error.
+// Note: This might also work for other *BSD OSs.
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ lib, err := registerFuncs()
+ if err != nil {
+ return "", err
+ }
+ defer lib.Close()
+
+ // Lock OS thread to ensure the errno does not change
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var vpi vnodePathInfo
+ const vpiSize = int32(unsafe.Sizeof(vpi))
+ ret := procPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize)
+ errno, _ := lib.Dlsym("errno")
+ err = *(**unix.Errno)(unsafe.Pointer(&errno))
+ if err == unix.EPERM {
+ return "", ErrorNotPermitted
+ }
+
+ if ret <= 0 {
+ return "", fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
+ }
+
+ if ret != vpiSize {
+ return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret)
+ }
+ return common.GoString(&vpi.vipPath[0]), nil
+}
+
+func procArgs(pid int32) ([]byte, int, error) {
+ procargs, _, err := common.CallSyscall([]int32{common.CTL_KERN, common.KERN_PROCARGS2, pid})
+ if err != nil {
+ return nil, 0, err
+ }
+
+ // The first 4 bytes indicate the number of arguments.
+ nargs := procargs[:4]
+ return procargs, int(binary.LittleEndian.Uint32(nargs)), nil
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return p.cmdlineSliceWithContext(ctx, true)
+}
+
+func (p *Process) cmdlineSliceWithContext(ctx context.Context, fallback bool) ([]string, error) {
+ pargs, nargs, err := procArgs(p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ // The first bytes hold the nargs int, skip it.
+ args := bytes.Split((pargs)[unsafe.Sizeof(int(0)):], []byte{0})
+ var argStr string
+ // The first element is the actual binary/command path.
+ // command := args[0]
+ var argSlice []string
+ // var envSlice []string
+ // All other, non-zero elements are arguments. The first "nargs" elements
+ // are the arguments. Everything else in the slice is then the environment
+ // of the process.
+ for _, arg := range args[1:] {
+ argStr = string(arg[:])
+ if len(argStr) > 0 {
+ if nargs > 0 {
+ argSlice = append(argSlice, argStr)
+ nargs--
+ continue
+ }
+ break
+ // envSlice = append(envSlice, argStr)
+ }
+ }
+ return argSlice, err
+}
+
+// cmdNameWithContext returns the command name (including spaces) without any arguments
+func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) {
+ r, err := p.cmdlineSliceWithContext(ctx, false)
+ if err != nil {
+ return "", err
+ }
+
+ if len(r) == 0 {
+ return "", nil
+ }
+
+ return r[0], err
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ r, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ return strings.Join(r, " "), err
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ lib, err := registerFuncs()
+ if err != nil {
+ return 0, err
+ }
+ defer lib.Close()
+
+ var ti ProcTaskInfo
+ procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+ return int32(ti.Threadnum), nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ lib, err := registerFuncs()
+ if err != nil {
+ return nil, err
+ }
+ defer lib.Close()
+
+ var ti ProcTaskInfo
+ procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+ timescaleToNanoSeconds := getTimeScaleToNanoSeconds()
+ ret := &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(ti.Total_user) * timescaleToNanoSeconds / 1e9,
+ System: float64(ti.Total_system) * timescaleToNanoSeconds / 1e9,
+ }
+ return ret, nil
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ lib, err := registerFuncs()
+ if err != nil {
+ return nil, err
+ }
+ defer lib.Close()
+
+ var ti ProcTaskInfo
+ procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+ ret := &MemoryInfoStat{
+ RSS: uint64(ti.Resident_size),
+ VMS: uint64(ti.Virtual_size),
+ Swap: uint64(ti.Pageins),
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go
new file mode 100644
index 0000000..890a5d5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package process
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Eproc struct {
+ Paddr *uint64
+ Sess *Session
+ Pcred Upcred
+ Ucred Uucred
+ Pad_cgo_0 [4]byte
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Pad_cgo_1 [2]byte
+ Tdev int32
+ Tpgid int32
+ Pad_cgo_2 [4]byte
+ Tsess *Session
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Pad_cgo_3 [2]byte
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ Pad_cgo_4 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct {
+ Link _Ctype_struct___0
+ Ref uint64
+ Posix Posix_cred
+ Label *Label
+ Audit Au_session
+}
+
+type Uucred struct {
+ Ref int32
+ UID uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+}
+
+type Upcred struct {
+ Pc_lock [72]int8
+ Pc_ucred *ucred
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+ Dummy int32
+ Pad_cgo_0 [4]byte
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Pad_cgo_1 [4]byte
+ Dummy4 [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+ P_un [16]byte
+ P_vmspace uint64
+ P_sigacts uint64
+ Pad_cgo_0 [3]byte
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ Pad_cgo_1 [4]byte
+ User_stack uint64
+ Exit_thread uint64
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ Pad_cgo_2 [4]byte
+ P_wchan uint64
+ P_wmesg uint64
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ Pad_cgo_3 [4]byte
+ P_tracep uint64
+ P_siglist int32
+ Pad_cgo_4 [4]byte
+ P_textvp uint64
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ Pad_cgo_5 [4]byte
+ P_pgrp uint64
+ P_addr uint64
+ P_xstat uint16
+ P_acflag uint16
+ Pad_cgo_6 [4]byte
+ P_ru uint64
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+ Aia_p *AuditinfoAddr
+ Mask AuMask
+}
+
+type Posix_cred struct {
+ UID uint32
+ Ruid uint32
+ Svuid uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+ Rgid uint32
+ Svgid uint32
+ Gmuid uint32
+ Flags int32
+}
+
+type Label struct{}
+
+type ProcTaskInfo struct {
+ Virtual_size uint64
+ Resident_size uint64
+ Total_user uint64
+ Total_system uint64
+ Threads_user uint64
+ Threads_system uint64
+ Policy int32
+ Faults int32
+ Pageins int32
+ Cow_faults int32
+ Messages_sent int32
+ Messages_received int32
+ Syscalls_mach int32
+ Syscalls_unix int32
+ Csw int32
+ Threadnum int32
+ Numrunning int32
+ Priority int32
+}
+
+type AuditinfoAddr struct {
+ Auid uint32
+ Mask AuMask
+ Termid AuTidAddr
+ Asid int32
+ Flags uint64
+}
+
+type AuMask struct {
+ Success uint32
+ Failure uint32
+}
+
+type AuTidAddr struct {
+ Port int32
+ Type uint32
+ Addr [4]uint32
+}
+
+type UcredQueue struct {
+ Next *ucred
+ Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go
new file mode 100644
index 0000000..8075cf2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_darwin.go
+
+package process
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Eproc struct {
+ Paddr *Proc
+ Sess *Session
+ Pcred Upcred
+ Ucred Uucred
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Tdev int32
+ Tpgid int32
+ Tsess *Session
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ Pad_cgo_0 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct{}
+
+type Uucred struct {
+ Ref int32
+ UID uint32
+ Ngroups int16
+ Groups [16]uint32
+}
+
+type Upcred struct {
+ Pc_lock [72]int8
+ Pc_ucred *ucred
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+ Dummy int32
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Dummy4 [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+ P_un [16]byte
+ P_vmspace uint64
+ P_sigacts uint64
+ Pad_cgo_0 [3]byte
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ Pad_cgo_1 [4]byte
+ User_stack uint64
+ Exit_thread uint64
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ Pad_cgo_2 [4]byte
+ P_wchan uint64
+ P_wmesg uint64
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ Pad_cgo_3 [4]byte
+ P_tracep uint64
+ P_siglist int32
+ Pad_cgo_4 [4]byte
+ P_textvp uint64
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ Pad_cgo_5 [4]byte
+ P_pgrp uint64
+ P_addr uint64
+ P_xstat uint16
+ P_acflag uint16
+ Pad_cgo_6 [4]byte
+ P_ru uint64
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+ Aia_p *AuditinfoAddr
+ Mask AuMask
+}
+
+type Posix_cred struct{}
+
+type Label struct{}
+
+type ProcTaskInfo struct {
+ Virtual_size uint64
+ Resident_size uint64
+ Total_user uint64
+ Total_system uint64
+ Threads_user uint64
+ Threads_system uint64
+ Policy int32
+ Faults int32
+ Pageins int32
+ Cow_faults int32
+ Messages_sent int32
+ Messages_received int32
+ Syscalls_mach int32
+ Syscalls_unix int32
+ Csw int32
+ Threadnum int32
+ Numrunning int32
+ Priority int32
+}
+
+type AuditinfoAddr struct {
+ Auid uint32
+ Mask AuMask
+ Termid AuTidAddr
+ Asid int32
+ Flags uint64
+}
+type AuMask struct {
+ Success uint32
+ Failure uint32
+}
+type AuTidAddr struct {
+ Port int32
+ Type uint32
+ Addr [4]uint32
+}
+
+type UcredQueue struct {
+ Next *ucred
+ Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go b/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go
new file mode 100644
index 0000000..e5410ea
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !plan9
+
+package process
+
+import (
+ "context"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+type Signal = syscall.Signal
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ return []string{""}, common.ErrNotImplementedError
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig Signal) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go
new file mode 100644
index 0000000..a67ac0e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "errors"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return ret, nil
+ }
+
+ for _, p := range procs {
+ ret = append(ret, p.Pid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+ name := common.IntToString(k.Comm[:])
+
+ if len(name) >= 15 {
+ cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ if len(cmdlineSlice) > 0 {
+ extendedName := filepath.Base(cmdlineSlice[0])
+ if strings.HasPrefix(extendedName, p.name) {
+ name = extendedName
+ }
+ }
+ }
+
+ return name, nil
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcCwd, p.Pid}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+
+ if length != sizeOfKinfoFile {
+ return "", errors.New("unexpected size of KinfoFile")
+ }
+
+ var k kinfoFile
+ br := bytes.NewReader(buf)
+ if err := common.Read(br, binary.LittleEndian, &k); err != nil {
+ return "", err
+ }
+ cwd := common.IntToString(k.Path[:])
+
+ return cwd, nil
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcPathname, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+
+ return strings.Trim(string(buf), "\x00"), nil
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+ ret := strings.FieldsFunc(string(buf), func(r rune) bool {
+ return r == '\u0000'
+ })
+
+ return strings.Join(ret, " "), nil
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) == 0 {
+ return nil, nil
+ }
+ if buf[len(buf)-1] == 0 {
+ buf = buf[:len(buf)-1]
+ }
+ parts := bytes.Split(buf, []byte{0})
+ var strParts []string
+ for _, p := range parts {
+ strParts = append(strParts, string(p))
+ }
+
+ return strParts, nil
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int64(k.Start.Sec)*1000 + int64(k.Start.Usec)/1000, nil
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return []string{""}, err
+ }
+ var s string
+ switch k.Stat {
+ case SIDL:
+ s = Idle
+ case SRUN:
+ s = Running
+ case SSLEEP:
+ s = Sleep
+ case SSTOP:
+ s = Stop
+ case SZOMB:
+ s = Zombie
+ case SWAIT:
+ s = Wait
+ case SLOCK:
+ s = Lock
+ }
+
+ return []string{s}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ uids := make([]uint32, 0, 3)
+
+ uids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))
+
+ return uids, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]uint32, 0, 3)
+ gids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))
+
+ return gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ groups := make([]uint32, k.Ngroups)
+ for i := int16(0); i < k.Ngroups; i++ {
+ groups[i] = uint32(k.Groups[i])
+ }
+
+ return groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Tdev)
+
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Nice), nil
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &IOCountersStat{
+ ReadCount: uint64(k.Rusage.Inblock),
+ WriteCount: uint64(k.Rusage.Oublock),
+ }, nil
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Numthreads, nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
+ System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
+ }, nil
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ v, err := unix.Sysctl("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ pageSize := common.LittleEndian.Uint16([]byte(v))
+
+ return &MemoryInfoStat{
+ RSS: uint64(k.Rssize) * uint64(pageSize),
+ VMS: uint64(k.Size),
+ }, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return nil, nil
+ }
+ ret := make([]*Process, 0, len(procs))
+ for _, proc := range procs {
+ ppid, err := proc.PpidWithContext(ctx)
+ if err != nil {
+ continue
+ }
+ if ppid == p.Pid {
+ ret = append(ret, proc)
+ }
+ }
+ sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+ return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ results := []*Process{}
+
+ mib := []int32{CTLKern, KernProc, KernProcProc, 0}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return results, err
+ }
+
+ // get kinfo_proc size
+ count := int(length / uint64(sizeOfKinfoProc))
+
+ // parse buf to procs
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+ k, err := parseKinfoProc(b)
+ if err != nil {
+ continue
+ }
+ p, err := NewProcessWithContext(ctx, int32(k.Pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+
+ return results, nil
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+ mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
+
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if length != sizeOfKinfoProc {
+ return nil, errors.New("unexpected size of KinfoProc")
+ }
+
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &k, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go
new file mode 100644
index 0000000..0193ba2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+ KernProcCwd = 42
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x300
+ sizeOfKinfoFile = 0x570 // TODO: should be changed by running on the target machine
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int32 /* pargs */
+ Paddr int32 /* proc */
+ Addr int32 /* user */
+ Tracep int32 /* vnode */
+ Textvp int32 /* vnode */
+ Fd int32 /* filedesc */
+ Vmspace int32 /* vmspace */
+ Wchan int32
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint32
+ Rssize int32
+ Swrss int32
+ Tsize int32
+ Dsize int32
+ Ssize int32
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int32
+ Kiflag int32
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu uint8
+ Lastcpu uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Sparestrings [50]int8
+ Spareints [7]int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int32 /* pcb */
+ Kstack int32
+ Udata int32
+ Tdaddr int32 /* thread */
+ Spareptrs [6]int32
+ Sparelongs [12]int32
+ Sflag int32
+ Tdflags int32
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev uint32
+ Vn_mode uint16
+ Status uint16
+ X_kve_ispare [12]int32
+ Path [1024]int8
+}
+
+// TODO: should be changed by running on the target machine
+type kinfoFile struct {
+ Structsize int32
+ Type int32
+ Fd int32
+ Ref_count int32
+ Flags int32
+ Pad0 int32
+ Offset int64
+ Anon0 [304]byte
+ Status uint16
+ Pad1 uint16
+ X_kf_ispare0 int32
+ Cap_rights capRights
+ X_kf_cap_spare uint64
+ Path [1024]int8 // changed from uint8 by hand
+}
+
+// TODO: should be changed by running on the target machine
+type capRights struct {
+ Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go
new file mode 100644
index 0000000..67970f6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+ KernProcCwd = 42
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x440
+ sizeOfKinfoFile = 0x570
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int64 /* pargs */
+ Paddr int64 /* proc */
+ Addr int64 /* user */
+ Tracep int64 /* vnode */
+ Textvp int64 /* vnode */
+ Fd int64 /* filedesc */
+ Vmspace int64 /* vmspace */
+ Wchan int64
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev_freebsd11 uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint64
+ Rssize int64
+ Swrss int64
+ Tsize int64
+ Dsize int64
+ Ssize int64
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int64
+ Kiflag int64
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu_old uint8
+ Lastcpu_old uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Moretdname [4]int8
+ Sparestrings [46]int8
+ Spareints [2]int32
+ Tdev uint64
+ Oncpu int32
+ Lastcpu int32
+ Tracer int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int64 /* pcb */
+ Kstack int64
+ Udata int64
+ Tdaddr int64 /* thread */
+ Pd int64 /* pwddesc, not accurate */
+ Spareptrs [5]int64
+ Sparelongs [12]int64
+ Sflag int64
+ Tdflags int64
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid_freebsd11 uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev_freebsd11 uint32
+ Vn_mode uint16
+ Status uint16
+ Type_spec [8]byte
+ Vn_rdev uint64
+ X_kve_ispare [8]int32
+ Path [1024]int8
+}
+
+type kinfoFile struct {
+ Structsize int32
+ Type int32
+ Fd int32
+ Ref_count int32
+ Flags int32
+ Pad0 int32
+ Offset int64
+ Anon0 [304]byte
+ Status uint16
+ Pad1 uint16
+ X_kf_ispare0 int32
+ Cap_rights capRights
+ X_kf_cap_spare uint64
+ Path [1024]int8
+}
+
+type capRights struct {
+ Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go
new file mode 100644
index 0000000..6c4fbf6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+ KernProcCwd = 42
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x440
+ sizeOfKinfoFile = 0x570 // TODO: should be changed by running on the target machine
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur int32
+ Max int32
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int32 /* pargs */
+ Paddr int32 /* proc */
+ Addr int32 /* user */
+ Tracep int32 /* vnode */
+ Textvp int32 /* vnode */
+ Fd int32 /* filedesc */
+ Vmspace int32 /* vmspace */
+ Wchan int32
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint32
+ Rssize int32
+ Swrss int32
+ Tsize int32
+ Dsize int32
+ Ssize int32
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int32
+ Kiflag int32
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu uint8
+ Lastcpu uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Sparestrings [50]int8
+ Spareints [4]int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int32 /* pcb */
+ Kstack int32
+ Udata int32
+ Tdaddr int32 /* thread */
+ Spareptrs [6]int64
+ Sparelongs [12]int64
+ Sflag int64
+ Tdflags int64
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev uint32
+ Vn_mode uint16
+ Status uint16
+ X_kve_ispare [12]int32
+ Path [1024]int8
+}
+
+// TODO: should be changed by running on the target machine
+type kinfoFile struct {
+ Structsize int32
+ Type int32
+ Fd int32
+ Ref_count int32
+ Flags int32
+ Pad0 int32
+ Offset int64
+ Anon0 [304]byte
+ Status uint16
+ Pad1 uint16
+ X_kf_ispare0 int32
+ Cap_rights capRights
+ X_kf_cap_spare uint64
+ Path [1024]int8 // changed from uint8 by hand
+}
+
+// TODO: should be changed by running on the target machine
+type capRights struct {
+ Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go
new file mode 100644
index 0000000..dabdc3e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+ KernProcCwd = 42
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x440
+ sizeOfKinfoFile = 0x570
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int64 /* pargs */
+ Paddr int64 /* proc */
+ Addr int64 /* user */
+ Tracep int64 /* vnode */
+ Textvp int64 /* vnode */
+ Fd int64 /* filedesc */
+ Vmspace int64 /* vmspace */
+ Wchan int64
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev_freebsd11 uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint64
+ Rssize int64
+ Swrss int64
+ Tsize int64
+ Dsize int64
+ Ssize int64
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int64
+ Kiflag int64
+ Traceflag int32
+ Stat uint8
+ Nice int8
+ Lock uint8
+ Rqindex uint8
+ Oncpu_old uint8
+ Lastcpu_old uint8
+ Tdname [17]uint8
+ Wmesg [9]uint8
+ Login [18]uint8
+ Lockname [9]uint8
+ Comm [20]int8 // changed from uint8 by hand
+ Emul [17]uint8
+ Loginclass [18]uint8
+ Moretdname [4]uint8
+ Sparestrings [46]uint8
+ Spareints [2]int32
+ Tdev uint64
+ Oncpu int32
+ Lastcpu int32
+ Tracer int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int64 /* pcb */
+ Kstack int64
+ Udata int64
+ Tdaddr int64 /* thread */
+ Pd int64 /* pwddesc, not accurate */
+ Spareptrs [5]int64
+ Sparelongs [12]int64
+ Sflag int64
+ Tdflags int64
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid_freebsd11 uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev_freebsd11 uint32
+ Vn_mode uint16
+ Status uint16
+ Type_spec [8]byte
+ Vn_rdev uint64
+ X_kve_ispare [8]int32
+ Path [1024]uint8
+}
+
+type kinfoFile struct {
+ Structsize int32
+ Type int32
+ Fd int32
+ Ref_count int32
+ Flags int32
+ Pad0 int32
+ Offset int64
+ Anon0 [304]byte
+ Status uint16
+ Pad1 uint16
+ X_kf_ispare0 int32
+ Cap_rights capRights
+ X_kf_cap_spare uint64
+ Path [1024]int8 // changed from uint8 by hand
+}
+
+type capRights struct {
+ Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go b/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go
new file mode 100644
index 0000000..68a8c88
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go
@@ -0,0 +1,1206 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package process
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "math"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/tklauser/go-sysconf"
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+var pageSize = uint64(os.Getpagesize())
+
+const prioProcess = 0 // linux/resource.h
+
+var clockTicks = 100 // default value
+
+func init() {
+ clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+ // ignore errors
+ if err == nil {
+ clockTicks = int(clkTck)
+ }
+}
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+ RSS uint64 `json:"rss"` // bytes
+ VMS uint64 `json:"vms"` // bytes
+ Shared uint64 `json:"shared"` // bytes
+ Text uint64 `json:"text"` // bytes
+ Lib uint64 `json:"lib"` // bytes
+ Data uint64 `json:"data"` // bytes
+ Dirty uint64 `json:"dirty"` // bytes
+}
+
+func (m MemoryInfoExStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+// String returns JSON value of the process.
+func (m MemoryMapsStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ _, ppid, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return -1, err
+ }
+ return ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ if p.name == "" {
+ if err := p.fillNameWithContext(ctx); err != nil {
+ return "", err
+ }
+ }
+ return p.name, nil
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ if p.tgid == 0 {
+ if err := p.fillFromStatusWithContext(ctx); err != nil {
+ return 0, err
+ }
+ }
+ return p.tgid, nil
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return p.fillFromExeWithContext(ctx)
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return p.fillFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return p.fillSliceFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ _, _, _, createTime, _, _, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ return createTime, nil
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return p.fillFromCwdWithContext(ctx)
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return []string{""}, err
+ }
+ return []string{p.status}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat")
+ contents, err := os.ReadFile(statPath)
+ if err != nil {
+ return false, err
+ }
+ fields := strings.Fields(string(contents))
+ if len(fields) < 8 {
+ return false, fmt.Errorf("insufficient data in %s", statPath)
+ }
+ pgid := fields[4]
+ tpgid := fields[7]
+ return pgid == tpgid, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return []uint32{}, err
+ }
+ return p.uids, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return []uint32{}, err
+ }
+ return p.gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return []uint32{}, err
+ }
+ return p.groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ t, _, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+ terminal := termmap[t]
+ return terminal, nil
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ _, _, _, _, _, nice, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ return nice, nil
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(ctx, false)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ rlimits, err := p.fillFromLimitsWithContext(ctx)
+ if !gatherUsed || err != nil {
+ return rlimits, err
+ }
+
+ _, _, _, _, rtprio, nice, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if err := p.fillFromStatusWithContext(ctx); err != nil {
+ return nil, err
+ }
+
+ for i := range rlimits {
+ rs := &rlimits[i]
+ switch rs.Resource {
+ case RLIMIT_CPU:
+ times, err := p.TimesWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ rs.Used = uint64(times.User + times.System)
+ case RLIMIT_DATA:
+ rs.Used = uint64(p.memInfo.Data)
+ case RLIMIT_STACK:
+ rs.Used = uint64(p.memInfo.Stack)
+ case RLIMIT_RSS:
+ rs.Used = uint64(p.memInfo.RSS)
+ case RLIMIT_NOFILE:
+ n, err := p.NumFDsWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ rs.Used = uint64(n)
+ case RLIMIT_MEMLOCK:
+ rs.Used = uint64(p.memInfo.Locked)
+ case RLIMIT_AS:
+ rs.Used = uint64(p.memInfo.VMS)
+ case RLIMIT_LOCKS:
+ // TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority.
+ case RLIMIT_SIGPENDING:
+ rs.Used = p.sigInfo.PendingProcess
+ case RLIMIT_NICE:
+ // The rlimit for nice is a little unusual, in that 0 means the niceness cannot be decreased beyond the current value, but it can be increased.
+ // So effectively: if rs.Soft == 0 { rs.Soft = rs.Used }
+ rs.Used = uint64(nice)
+ case RLIMIT_RTPRIO:
+ rs.Used = uint64(rtprio)
+ }
+ }
+
+ return rlimits, err
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return p.fillFromIOWithContext(ctx)
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return p.numCtxSwitches, nil
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ _, fnames, err := p.fillFromfdListWithContext(ctx)
+ return int32(len(fnames)), err
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ err := p.fillFromStatusWithContext(ctx)
+ if err != nil {
+ return 0, err
+ }
+ return p.numThreads, nil
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ taskPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "task")
+
+ tids, err := readPidsFromDir(taskPath)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, tid := range tids {
+ _, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStatWithContext(ctx, tid)
+ if err != nil {
+ return nil, err
+ }
+ ret[tid] = cpuTimes
+ }
+
+ return ret, nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ _, _, cpuTimes, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return cpuTimes, nil
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ meminfo, _, err := p.fillFromStatmWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return meminfo, nil
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ _, memInfoEx, err := p.fillFromStatmWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return memInfoEx, nil
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ _, _, _, _, _, _, pageFaults, err := p.fillFromStatWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return pageFaults, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ statFiles, err := filepath.Glob(common.HostProcWithContext(ctx, "[0-9]*/stat"))
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]*Process, 0, len(statFiles))
+ for _, statFile := range statFiles {
+ statContents, err := os.ReadFile(statFile)
+ if err != nil {
+ continue
+ }
+ fields := splitProcStat(statContents)
+ pid, err := strconv.ParseInt(fields[1], 10, 32)
+ if err != nil {
+ continue
+ }
+ ppid, err := strconv.ParseInt(fields[4], 10, 32)
+ if err != nil {
+ continue
+ }
+ if int32(ppid) == p.Pid {
+ np, err := NewProcessWithContext(ctx, int32(pid))
+ if err != nil {
+ continue
+ }
+ ret = append(ret, np)
+ }
+ }
+ sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+ return ret, nil
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ _, ofs, err := p.fillFromfdWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]OpenFilesStat, len(ofs))
+ for i, o := range ofs {
+ ret[i] = *o
+ }
+
+ return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ pid := p.Pid
+ var ret []MemoryMapsStat
+ smapsPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps")
+ if grouped {
+ ret = make([]MemoryMapsStat, 1)
+ // If smaps_rollup exists (require kernel >= 4.15), then we will use it
+ // for pre-summed memory information for a process.
+ smapsRollupPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps_rollup")
+ if _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) {
+ smapsPath = smapsRollupPath
+ }
+ }
+ contents, err := os.ReadFile(smapsPath)
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(contents), "\n")
+
+ // function of parsing a block
+ getBlock := func(firstLine []string, block []string) (MemoryMapsStat, error) {
+ m := MemoryMapsStat{}
+ if len(firstLine) >= 6 {
+ m.Path = strings.Join(firstLine[5:], " ")
+ }
+
+ for _, line := range block {
+ if strings.Contains(line, "VmFlags") {
+ continue
+ }
+ field := strings.Split(line, ":")
+ if len(field) < 2 {
+ continue
+ }
+ v := strings.Trim(field[1], "kB") // remove last "kB"
+ v = strings.TrimSpace(v)
+ t, err := strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return m, err
+ }
+
+ switch field[0] {
+ case "Size":
+ m.Size = t
+ case "Rss":
+ m.Rss = t
+ case "Pss":
+ m.Pss = t
+ case "Shared_Clean":
+ m.SharedClean = t
+ case "Shared_Dirty":
+ m.SharedDirty = t
+ case "Private_Clean":
+ m.PrivateClean = t
+ case "Private_Dirty":
+ m.PrivateDirty = t
+ case "Referenced":
+ m.Referenced = t
+ case "Anonymous":
+ m.Anonymous = t
+ case "Swap":
+ m.Swap = t
+ }
+ }
+ return m, nil
+ }
+
+ var firstLine []string
+ blocks := make([]string, 0, 16)
+
+ for i, line := range lines {
+ fields := strings.Fields(line)
+ if (len(fields) > 0 && !strings.HasSuffix(fields[0], ":")) || i == len(lines)-1 {
+ // new block section
+ if len(firstLine) > 0 && len(blocks) > 0 {
+ g, err := getBlock(firstLine, blocks)
+ if err != nil {
+ return &ret, err
+ }
+ if grouped {
+ ret[0].Size += g.Size
+ ret[0].Rss += g.Rss
+ ret[0].Pss += g.Pss
+ ret[0].SharedClean += g.SharedClean
+ ret[0].SharedDirty += g.SharedDirty
+ ret[0].PrivateClean += g.PrivateClean
+ ret[0].PrivateDirty += g.PrivateDirty
+ ret[0].Referenced += g.Referenced
+ ret[0].Anonymous += g.Anonymous
+ ret[0].Swap += g.Swap
+ } else {
+ ret = append(ret, g)
+ }
+ }
+ // starts new block
+ blocks = make([]string, 0, 16)
+ firstLine = fields
+ } else {
+ blocks = append(blocks, line)
+ }
+ }
+
+ return &ret, nil
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ")
+
+ environContent, err := os.ReadFile(environPath)
+ if err != nil {
+ return nil, err
+ }
+
+ return strings.Split(string(environContent), "\000"), nil
+}
+
+/**
+** Internal functions
+**/
+
+func limitToUint(val string) (uint64, error) {
+ if val == "unlimited" {
+ return math.MaxUint64, nil
+ }
+ res, err := strconv.ParseUint(val, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return res, nil
+}
+
+// Get num_fds from /proc/(pid)/limits
+func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) {
+ pid := p.Pid
+ limitsFile := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "limits")
+ d, err := os.Open(limitsFile)
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ var limitStats []RlimitStat
+
+ limitsScanner := bufio.NewScanner(d)
+ for limitsScanner.Scan() {
+ var statItem RlimitStat
+
+ str := strings.Fields(limitsScanner.Text())
+
+ // Remove the header line
+ if strings.Contains(str[len(str)-1], "Units") {
+ continue
+ }
+
+ // Assert that last item is a Hard limit
+ statItem.Hard, err = limitToUint(str[len(str)-1])
+ if err != nil {
+ // On error remove last item and try once again since it can be unit or header line
+ str = str[:len(str)-1]
+ statItem.Hard, err = limitToUint(str[len(str)-1])
+ if err != nil {
+ return nil, err
+ }
+ }
+ // Remove last item from string
+ str = str[:len(str)-1]
+
+ // Now last item is a Soft limit
+ statItem.Soft, err = limitToUint(str[len(str)-1])
+ if err != nil {
+ return nil, err
+ }
+ // Remove last item from string
+ str = str[:len(str)-1]
+
+ // The rest is a stats name
+ resourceName := strings.Join(str, " ")
+ switch resourceName {
+ case "Max cpu time":
+ statItem.Resource = RLIMIT_CPU
+ case "Max file size":
+ statItem.Resource = RLIMIT_FSIZE
+ case "Max data size":
+ statItem.Resource = RLIMIT_DATA
+ case "Max stack size":
+ statItem.Resource = RLIMIT_STACK
+ case "Max core file size":
+ statItem.Resource = RLIMIT_CORE
+ case "Max resident set":
+ statItem.Resource = RLIMIT_RSS
+ case "Max processes":
+ statItem.Resource = RLIMIT_NPROC
+ case "Max open files":
+ statItem.Resource = RLIMIT_NOFILE
+ case "Max locked memory":
+ statItem.Resource = RLIMIT_MEMLOCK
+ case "Max address space":
+ statItem.Resource = RLIMIT_AS
+ case "Max file locks":
+ statItem.Resource = RLIMIT_LOCKS
+ case "Max pending signals":
+ statItem.Resource = RLIMIT_SIGPENDING
+ case "Max msgqueue size":
+ statItem.Resource = RLIMIT_MSGQUEUE
+ case "Max nice priority":
+ statItem.Resource = RLIMIT_NICE
+ case "Max realtime priority":
+ statItem.Resource = RLIMIT_RTPRIO
+ case "Max realtime timeout":
+ statItem.Resource = RLIMIT_RTTIME
+ default:
+ continue
+ }
+
+ limitStats = append(limitStats, statItem)
+ }
+
+ if err := limitsScanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return limitStats, nil
+}
+
+// Get list of /proc/(pid)/fd files
+func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd")
+ d, err := os.Open(statPath)
+ if err != nil {
+ return statPath, []string{}, err
+ }
+ defer d.Close()
+ fnames, err := d.Readdirnames(-1)
+ return statPath, fnames, err
+}
+
+// Get num_fds from /proc/(pid)/fd
+func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFilesStat, error) {
+ statPath, fnames, err := p.fillFromfdListWithContext(ctx)
+ if err != nil {
+ return 0, nil, err
+ }
+ numFDs := int32(len(fnames))
+
+ var openfiles []*OpenFilesStat
+ for _, fd := range fnames {
+ fpath := filepath.Join(statPath, fd)
+ filepath, err := os.Readlink(fpath)
+ if err != nil {
+ continue
+ }
+ t, err := strconv.ParseUint(fd, 10, 64)
+ if err != nil {
+ return numFDs, openfiles, err
+ }
+ o := &OpenFilesStat{
+ Path: filepath,
+ Fd: t,
+ }
+ openfiles = append(openfiles, o)
+ }
+
+ return numFDs, openfiles, nil
+}
+
+// Get cwd from /proc/(pid)/cwd
+func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cwd")
+ cwd, err := os.Readlink(cwdPath)
+ if err != nil {
+ return "", err
+ }
+ return string(cwd), nil
+}
+
+// Get exe from /proc/(pid)/exe
+func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ exePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "exe")
+ exe, err := os.Readlink(exePath)
+ if err != nil {
+ return "", err
+ }
+ return string(exe), nil
+}
+
+// Get cmdline from /proc/(pid)/cmdline
+func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := os.ReadFile(cmdPath)
+ if err != nil {
+ return "", err
+ }
+ ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
+ return r == '\u0000'
+ })
+
+ return strings.Join(ret, " "), nil
+}
+
+func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := os.ReadFile(cmdPath)
+ if err != nil {
+ return nil, err
+ }
+ if len(cmdline) == 0 {
+ return nil, nil
+ }
+
+ cmdline = bytes.TrimRight(cmdline, "\x00")
+
+ parts := bytes.Split(cmdline, []byte{0})
+ var strParts []string
+ for _, p := range parts {
+ strParts = append(strParts, string(p))
+ }
+
+ return strParts, nil
+}
+
+// Get IO status from /proc/(pid)/io
+func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {
+ pid := p.Pid
+ ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io")
+ ioline, err := os.ReadFile(ioPath)
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(ioline), "\n")
+ ret := &IOCountersStat{}
+
+ for _, line := range lines {
+ field := strings.Fields(line)
+ if len(field) < 2 {
+ continue
+ }
+ t, err := strconv.ParseUint(field[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ param := strings.TrimSuffix(field[0], ":")
+ switch param {
+ case "syscr":
+ ret.ReadCount = t
+ case "syscw":
+ ret.WriteCount = t
+ case "read_bytes":
+ ret.DiskReadBytes = t
+ case "write_bytes":
+ ret.DiskWriteBytes = t
+ case "rchar":
+ ret.ReadBytes = t
+ case "wchar":
+ ret.WriteBytes = t
+ }
+ }
+
+ return ret, nil
+}
+
+// Get memory info from /proc/(pid)/statm
+func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {
+ pid := p.Pid
+ memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm")
+ contents, err := os.ReadFile(memPath)
+ if err != nil {
+ return nil, nil, err
+ }
+ fields := strings.Split(string(contents), " ")
+
+ vms, err := strconv.ParseUint(fields[0], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ rss, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ memInfo := &MemoryInfoStat{
+ RSS: rss * pageSize,
+ VMS: vms * pageSize,
+ }
+
+ shared, err := strconv.ParseUint(fields[2], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ text, err := strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ lib, err := strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ dirty, err := strconv.ParseUint(fields[5], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ memInfoEx := &MemoryInfoExStat{
+ RSS: rss * pageSize,
+ VMS: vms * pageSize,
+ Shared: shared * pageSize,
+ Text: text * pageSize,
+ Lib: lib * pageSize,
+ Dirty: dirty * pageSize,
+ }
+
+ return memInfo, memInfoEx, nil
+}
+
+// Get name from /proc/(pid)/comm or /proc/(pid)/status
+func (p *Process) fillNameWithContext(ctx context.Context) error {
+ err := p.fillFromCommWithContext(ctx)
+ if err == nil && p.name != "" && len(p.name) < 15 {
+ return nil
+ }
+ return p.fillFromStatusWithContext(ctx)
+}
+
+// Get name from /proc/(pid)/comm
+func (p *Process) fillFromCommWithContext(ctx context.Context) error {
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm")
+ contents, err := os.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+
+ p.name = strings.TrimSuffix(string(contents), "\n")
+ return nil
+}
+
+// Get various status from /proc/(pid)/status
+func (p *Process) fillFromStatus() error {
+ return p.fillFromStatusWithContext(context.Background())
+}
+
+func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
+ contents, err := os.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(contents), "\n")
+ p.numCtxSwitches = &NumCtxSwitchesStat{}
+ p.memInfo = &MemoryInfoStat{}
+ p.sigInfo = &SignalInfoStat{}
+ for _, line := range lines {
+ tabParts := strings.SplitN(line, "\t", 2)
+ if len(tabParts) < 2 {
+ continue
+ }
+ value := tabParts[1]
+ switch strings.TrimRight(tabParts[0], ":") {
+ case "Name":
+ p.name = strings.Trim(value, " \t")
+ if len(p.name) >= 15 {
+ cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return err
+ }
+ if len(cmdlineSlice) > 0 {
+ extendedName := filepath.Base(cmdlineSlice[0])
+ if strings.HasPrefix(extendedName, p.name) {
+ p.name = extendedName
+ }
+ }
+ }
+ // Ensure we have a copy and not reference into slice
+ p.name = string([]byte(p.name))
+ case "State":
+ p.status = convertStatusChar(value[0:1])
+ // Ensure we have a copy and not reference into slice
+ p.status = string([]byte(p.status))
+ case "PPid", "Ppid":
+ pval, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.parent = int32(pval)
+ case "Tgid":
+ pval, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.tgid = int32(pval)
+ case "Uid":
+ p.uids = make([]uint32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.uids = append(p.uids, uint32(v))
+ }
+ case "Gid":
+ p.gids = make([]uint32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.gids = append(p.gids, uint32(v))
+ }
+ case "Groups":
+ groups := strings.Fields(value)
+ p.groups = make([]uint32, 0, len(groups))
+ for _, i := range groups {
+ v, err := strconv.ParseUint(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.groups = append(p.groups, uint32(v))
+ }
+ case "Threads":
+ v, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.numThreads = int32(v)
+ case "voluntary_ctxt_switches":
+ v, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.numCtxSwitches.Voluntary = v
+ case "nonvoluntary_ctxt_switches":
+ v, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.numCtxSwitches.Involuntary = v
+ case "VmRSS":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.RSS = v * 1024
+ case "VmSize":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.VMS = v * 1024
+ case "VmSwap":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Swap = v * 1024
+ case "VmHWM":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.HWM = v * 1024
+ case "VmData":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Data = v * 1024
+ case "VmStk":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Stack = v * 1024
+ case "VmLck":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Locked = v * 1024
+ case "SigPnd":
+ if len(value) > 16 {
+ value = value[len(value)-16:]
+ }
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.PendingThread = v
+ case "ShdPnd":
+ if len(value) > 16 {
+ value = value[len(value)-16:]
+ }
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.PendingProcess = v
+ case "SigBlk":
+ if len(value) > 16 {
+ value = value[len(value)-16:]
+ }
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Blocked = v
+ case "SigIgn":
+ if len(value) > 16 {
+ value = value[len(value)-16:]
+ }
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Ignored = v
+ case "SigCgt":
+ if len(value) > 16 {
+ value = value[len(value)-16:]
+ }
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Caught = v
+ }
+
+ }
+ return nil
+}
+
+func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+ return p.fillFromTIDStatWithContext(context.Background(), tid)
+}
+
+func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+ pid := p.Pid
+ var statPath string
+
+ if tid == -1 {
+ statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat")
+ } else {
+ statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat")
+ }
+
+ contents, err := os.ReadFile(statPath)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ // Indexing from one, as described in `man proc` about the file /proc/[pid]/stat
+ fields := splitProcStat(contents)
+
+ terminal, err := strconv.ParseUint(fields[7], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+
+ ppid, err := strconv.ParseInt(fields[4], 10, 32)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ utime, err := strconv.ParseFloat(fields[14], 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+
+ stime, err := strconv.ParseFloat(fields[15], 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+
+ // There is no such thing as iotime in stat file. As an approximation, we
+ // will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux
+ // docs). Note: I am assuming at least Linux 2.6.18
+ var iotime float64
+ if len(fields) > 42 {
+ iotime, err = strconv.ParseFloat(fields[42], 64)
+ if err != nil {
+ iotime = 0 // Ancient linux version, most likely
+ }
+ } else {
+ iotime = 0 // e.g. SmartOS containers
+ }
+
+ cpuTimes := &cpu.TimesStat{
+ CPU: "cpu",
+ User: utime / float64(clockTicks),
+ System: stime / float64(clockTicks),
+ Iowait: iotime / float64(clockTicks),
+ }
+
+ bootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache)
+ t, err := strconv.ParseUint(fields[22], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ createTime := int64((t * 1000 / uint64(clockTicks)) + uint64(bootTime*1000))
+
+ rtpriority, err := strconv.ParseInt(fields[18], 10, 32)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ if rtpriority < 0 {
+ rtpriority = rtpriority*-1 - 1
+ } else {
+ rtpriority = 0
+ }
+
+ // p.Nice = mustParseInt32(fields[18])
+ // use syscall instead of parse Stat file
+ snice, _ := unix.Getpriority(prioProcess, int(pid))
+ nice := int32(snice) // FIXME: is this true?
+
+ minFault, err := strconv.ParseUint(fields[10], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ cMinFault, err := strconv.ParseUint(fields[11], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ majFault, err := strconv.ParseUint(fields[12], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+ cMajFault, err := strconv.ParseUint(fields[13], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, nil, err
+ }
+
+ faults := &PageFaultsStat{
+ MinorFaults: minFault,
+ MajorFaults: majFault,
+ ChildMinorFaults: cMinFault,
+ ChildMajorFaults: cMajFault,
+ }
+
+ return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil
+}
+
+func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+ return p.fillFromTIDStatWithContext(ctx, -1)
+}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ return readPidsFromDir(common.HostProcWithContext(ctx))
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, err
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcessWithContext(ctx, pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func readPidsFromDir(path string) ([]int32, error) {
+ var ret []int32
+
+ d, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ fnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, fname := range fnames {
+ pid, err := strconv.ParseInt(fname, 10, 32)
+ if err != nil {
+ // if not numeric name, just skip
+ continue
+ }
+ ret = append(ret, int32(pid))
+ }
+
+ return ret, nil
+}
+
+func splitProcStat(content []byte) []string {
+ nameStart := bytes.IndexByte(content, '(')
+ nameEnd := bytes.LastIndexByte(content, ')')
+ restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '
+ name := content[nameStart+1 : nameEnd]
+ pid := strings.TrimSpace(string(content[:nameStart]))
+ fields := make([]string, 3, len(restFields)+3)
+ fields[1] = string(pid)
+ fields[2] = string(name)
+ fields = append(fields, restFields...)
+ return fields
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
new file mode 100644
index 0000000..5e8a9e0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ cpu "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ mem "github.com/shirou/gopsutil/v4/mem"
+ net "github.com/shirou/gopsutil/v4/net"
+ "golang.org/x/sys/unix"
+)
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return ret, nil
+ }
+
+ for _, p := range procs {
+ ret = append(ret, p.Pid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+ name := common.IntToString(k.Comm[:])
+
+ if len(name) >= 15 {
+ cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ if len(cmdlineSlice) > 0 {
+ extendedName := filepath.Base(cmdlineSlice[0])
+ if strings.HasPrefix(extendedName, p.name) {
+ name = extendedName
+ }
+ }
+ }
+
+ return name, nil
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProcCwd, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+ return common.ByteToString(buf), nil
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+
+ /* From man sysctl(2):
+ The buffer pointed to by oldp is filled with an array of char
+ pointers followed by the strings themselves. The last char
+ pointer is a NULL pointer. */
+ var strParts []string
+ r := bytes.NewReader(buf)
+ baseAddr := uintptr(unsafe.Pointer(&buf[0]))
+ for {
+ argvp, err := readPtr(r)
+ if err != nil {
+ return nil, err
+ }
+ if argvp == 0 { // check for a NULL pointer
+ break
+ }
+ offset := argvp - baseAddr
+ length := uintptr(bytes.IndexByte(buf[offset:], 0))
+ str := string(buf[offset : offset+length])
+ strParts = append(strParts, str)
+ }
+
+ return strParts, nil
+}
+
+// readPtr reads a pointer data from a given reader. WARNING: only little
+// endian architectures are supported.
+func readPtr(r io.Reader) (uintptr, error) {
+ switch sizeofPtr {
+ case 4:
+ var p uint32
+ if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+ return 0, err
+ }
+ return uintptr(p), nil
+ case 8:
+ var p uint64
+ if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+ return 0, err
+ }
+ return uintptr(p), nil
+ default:
+ return 0, fmt.Errorf("unsupported pointer size")
+ }
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ argv, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ return strings.Join(argv, " "), nil
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return []string{""}, err
+ }
+ var s string
+ switch k.Stat {
+ case SIDL:
+ case SRUN:
+ case SONPROC:
+ s = Running
+ case SSLEEP:
+ s = Sleep
+ case SSTOP:
+ s = Stop
+ case SDEAD:
+ s = Zombie
+ }
+
+ return []string{s}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ uids := make([]uint32, 0, 3)
+
+ uids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))
+
+ return uids, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]uint32, 0, 3)
+ gids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))
+
+ return gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ groups := make([]uint32, k.Ngroups)
+ for i := int16(0); i < k.Ngroups; i++ {
+ groups[i] = uint32(k.Groups[i])
+ }
+
+ return groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Tdev)
+
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Nice), nil
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &IOCountersStat{
+ ReadCount: uint64(k.Uru_inblock),
+ WriteCount: uint64(k.Uru_oublock),
+ }, nil
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ /* not supported, just return 1 */
+ return 1, nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
+ System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
+ }, nil
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ pageSize, err := mem.GetPageSizeWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return &MemoryInfoStat{
+ RSS: uint64(k.Vm_rssize) * pageSize,
+ VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
+ uint64(k.Vm_ssize),
+ }, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return nil, nil
+ }
+ ret := make([]*Process, 0, len(procs))
+ for _, proc := range procs {
+ ppid, err := proc.PpidWithContext(ctx)
+ if err != nil {
+ continue
+ }
+ if ppid == p.Pid {
+ ret = append(ret, proc)
+ }
+ }
+ sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+ return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ results := []*Process{}
+
+ buf, length, err := callKernProcSyscall(KernProcAll, 0)
+ if err != nil {
+ return results, err
+ }
+
+ // get kinfo_proc size
+ count := int(length / uint64(sizeOfKinfoProc))
+
+ // parse buf to procs
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+ k, err := parseKinfoProc(b)
+ if err != nil {
+ continue
+ }
+ p, err := NewProcessWithContext(ctx, int32(k.Pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+
+ return results, nil
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+ buf, length, err := callKernProcSyscall(KernProcPID, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ if length != sizeOfKinfoProc {
+ return nil, errors.New("unexpected size of KinfoProc")
+ }
+
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &k, nil
+}
+
+func callKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
+ mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return nil, length, err
+ }
+
+ count := int32(length / uint64(sizeOfKinfoProc))
+ mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
+ mibptr = unsafe.Pointer(&mib[0])
+ miblen = uint64(len(mib))
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go
new file mode 100644
index 0000000..5b84706
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && 386
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcCwd = 78
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x38
+ sizeOfKinfoProc = 0x264
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Acflag uint16
+ Comm [24]int8
+ Wmesg [8]int8
+ Wchan uint64
+ Login [32]int8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags int32
+ Spare int32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]int8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint32
+ End uint32
+ Guard uint32
+ Fspace uint32
+ Fspace_augment uint32
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go
new file mode 100644
index 0000000..3229bb3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcCwd = 78
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x50
+ sizeOfKinfoProc = 0x268
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Acflag uint16
+ Comm [24]int8
+ Wmesg [8]int8
+ Wchan uint64
+ Login [32]int8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Pad_cgo_0 [4]byte
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags int32
+ Spare int32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]int8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint64
+ End uint64
+ Guard uint64
+ Fspace uint64
+ Fspace_augment uint64
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go
new file mode 100644
index 0000000..6f74ce7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcCwd = 78
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x38
+ sizeOfKinfoProc = 0x264
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Acflag uint16
+ Comm [24]int8
+ Wmesg [8]int8
+ Wchan uint64
+ Login [32]int8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags int32
+ Spare int32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]int8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint32
+ End uint32
+ Guard uint32
+ Fspace uint32
+ Fspace_augment uint32
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go
new file mode 100644
index 0000000..9104545
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcCwd = 78
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x50
+ sizeOfKinfoProc = 0x270
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Acflag uint16
+ Comm [24]int8
+ Wmesg [8]uint8
+ Wchan uint64
+ Login [32]uint8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags uint32
+ Spare int32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]uint8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+ Pledge uint64
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint64
+ End uint64
+ Guard uint64
+ Fspace uint64
+ Fspace_augment uint64
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go
new file mode 100644
index 0000000..e3e0d36
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && riscv64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcCwd = 78
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x50
+ sizeOfKinfoProc = 0x288
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Spare uint16
+ Comm [24]int8
+ Wmesg [8]uint8
+ Wchan uint64
+ Login [32]uint8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags uint32
+ Acflag uint32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]uint8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+ Pledge uint64
+ Name [24]uint8
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint64
+ End uint64
+ Guard uint64
+ Fspace uint64
+ Fspace_augment uint64
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go b/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go
new file mode 100644
index 0000000..c82e54a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package process
+
+import (
+ "context"
+ "syscall"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+type Signal = syscall.Note
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ return []string{""}, common.ErrNotImplementedError
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig Signal) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go b/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go
new file mode 100644
index 0000000..96c5e06
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux || freebsd || openbsd || darwin || solaris
+
+package process
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type Signal = syscall.Signal
+
+// POSIX
+func getTerminalMap() (map[uint64]string, error) {
+ ret := make(map[uint64]string)
+ var termfiles []string
+
+ d, err := os.Open("/dev")
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ devnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, devname := range devnames {
+ if strings.HasPrefix(devname, "/dev/tty") {
+ termfiles = append(termfiles, "/dev/tty/"+devname)
+ }
+ }
+
+ var ptsnames []string
+ ptsd, err := os.Open("/dev/pts")
+ if err != nil {
+ ptsnames, _ = filepath.Glob("/dev/ttyp*")
+ if ptsnames == nil {
+ return nil, err
+ }
+ }
+ defer ptsd.Close()
+
+ if ptsnames == nil {
+ defer ptsd.Close()
+ ptsnames, err = ptsd.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, ptsname := range ptsnames {
+ termfiles = append(termfiles, "/dev/pts/"+ptsname)
+ }
+ } else {
+ termfiles = ptsnames
+ }
+
+ for _, name := range termfiles {
+ stat := unix.Stat_t{}
+ if err = unix.Stat(name, &stat); err != nil {
+ return nil, err
+ }
+ rdev := uint64(stat.Rdev)
+ ret[rdev] = strings.Replace(name, "/dev", "", -1)
+ }
+ return ret, nil
+}
+
+// isMount is a port of python's os.path.ismount()
+// https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216
+// https://docs.python.org/3/library/os.path.html#os.path.ismount
+func isMount(path string) bool {
+ // Check symlinkness with os.Lstat; unix.DT_LNK is not portable
+ fileInfo, err := os.Lstat(path)
+ if err != nil {
+ return false
+ }
+ if fileInfo.Mode()&os.ModeSymlink != 0 {
+ return false
+ }
+ var stat1 unix.Stat_t
+ if err := unix.Lstat(path, &stat1); err != nil {
+ return false
+ }
+ parent := filepath.Join(path, "..")
+ var stat2 unix.Stat_t
+ if err := unix.Lstat(parent, &stat2); err != nil {
+ return false
+ }
+ return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+ if pid <= 0 {
+ return false, fmt.Errorf("invalid pid %v", pid)
+ }
+ proc, err := os.FindProcess(int(pid))
+ if err != nil {
+ return false, err
+ }
+ defer proc.Release()
+
+ if isMount(common.HostProcWithContext(ctx)) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
+ _, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid))))
+ if os.IsNotExist(err) {
+ return false, nil
+ }
+ return err == nil, err
+ }
+
+ // procfs does not exist or is not mounted, check PID existence by signalling the pid
+ err = proc.Signal(syscall.Signal(0))
+ if err == nil {
+ return true, nil
+ }
+ if errors.Is(err, os.ErrProcessDone) {
+ return false, nil
+ }
+ var errno syscall.Errno
+ if !errors.As(err, &errno) {
+ return false, err
+ }
+ switch errno {
+ case syscall.ESRCH:
+ return false, nil
+ case syscall.EPERM:
+ return true, nil
+ }
+
+ return false, err
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
+ process, err := os.FindProcess(int(p.Pid))
+ if err != nil {
+ return err
+ }
+ defer process.Release()
+
+ err = process.Signal(sig)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return p.SendSignalWithContext(ctx, unix.SIGSTOP)
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return p.SendSignalWithContext(ctx, unix.SIGCONT)
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ return p.SendSignalWithContext(ctx, unix.SIGTERM)
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ return p.SendSignalWithContext(ctx, unix.SIGKILL)
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ uids, err := p.UidsWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ if len(uids) > 0 {
+ u, err := user.LookupId(strconv.Itoa(int(uids[0])))
+ if err != nil {
+ return "", err
+ }
+ return u.Username, nil
+ }
+ return "", nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go b/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go
new file mode 100644
index 0000000..5c8d4d3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package process
+
+import (
+ "bytes"
+ "context"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+)
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ return readPidsFromDir(common.HostProcWithContext(ctx))
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, err
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcessWithContext(ctx, pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ exe, err := p.fillFromPathAOutWithContext(ctx)
+ if os.IsNotExist(err) {
+ exe, err = p.fillFromExecnameWithContext(ctx)
+ }
+ return exe, err
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return p.fillFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return p.fillSliceFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return p.fillFromPathCwdWithContext(ctx)
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ return []string{""}, common.ErrNotImplementedError
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ _, fnames, err := p.fillFromfdListWithContext(ctx)
+ return int32(len(fnames)), err
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+/**
+** Internal functions
+**/
+
+func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
+ pid := p.Pid
+ statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd")
+ d, err := os.Open(statPath)
+ if err != nil {
+ return statPath, []string{}, err
+ }
+ defer d.Close()
+ fnames, err := d.Readdirnames(-1)
+ return statPath, fnames, err
+}
+
+func (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "cwd")
+ cwd, err := os.Readlink(cwdPath)
+ if err != nil {
+ return "", err
+ }
+ return cwd, nil
+}
+
+func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "a.out")
+ exe, err := os.Readlink(cwdPath)
+ if err != nil {
+ return "", err
+ }
+ return exe, nil
+}
+
+func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname")
+ exe, err := os.ReadFile(execNamePath)
+ if err != nil {
+ return "", err
+ }
+ return string(exe), nil
+}
+
+func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := os.ReadFile(cmdPath)
+ if err != nil {
+ return "", err
+ }
+ ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
+ if r == '\u0000' {
+ return true
+ }
+ return false
+ })
+
+ return strings.Join(ret, " "), nil
+}
+
+func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := os.ReadFile(cmdPath)
+ if err != nil {
+ return nil, err
+ }
+ if len(cmdline) == 0 {
+ return nil, nil
+ }
+ if cmdline[len(cmdline)-1] == 0 {
+ cmdline = cmdline[:len(cmdline)-1]
+ }
+ parts := bytes.Split(cmdline, []byte{0})
+ var strParts []string
+ for _, p := range parts {
+ strParts = append(strParts, string(p))
+ }
+
+ return strParts, nil
+}
+
+func readPidsFromDir(path string) ([]int32, error) {
+ var ret []int32
+
+ d, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ fnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, fname := range fnames {
+ pid, err := strconv.ParseInt(fname, 10, 32)
+ if err != nil {
+ // if not numeric name, just skip
+ continue
+ }
+ ret = append(ret, int32(pid))
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go
new file mode 100644
index 0000000..012886d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go
@@ -0,0 +1,1180 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package process
+
+import (
+ "bufio"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "syscall"
+ "time"
+ "unicode/utf16"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "github.com/shirou/gopsutil/v4/net"
+ "golang.org/x/sys/windows"
+)
+
+type Signal = syscall.Signal
+
+var (
+ modntdll = windows.NewLazySystemDLL("ntdll.dll")
+ procNtResumeProcess = modntdll.NewProc("NtResumeProcess")
+ procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
+
+ modpsapi = windows.NewLazySystemDLL("psapi.dll")
+ procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
+ procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW")
+
+ advapi32 = windows.NewLazySystemDLL("advapi32.dll")
+ procLookupPrivilegeValue = advapi32.NewProc("LookupPrivilegeValueW")
+ procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
+
+ procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW")
+ procGetPriorityClass = common.Modkernel32.NewProc("GetPriorityClass")
+ procGetProcessIoCounters = common.Modkernel32.NewProc("GetProcessIoCounters")
+ procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
+ procGetProcessHandleCount = common.Modkernel32.NewProc("GetProcessHandleCount")
+
+ processorArchitecture uint
+)
+
+const processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION
+
+type systemProcessorInformation struct {
+ ProcessorArchitecture uint16
+ ProcessorLevel uint16
+ ProcessorRevision uint16
+ Reserved uint16
+ ProcessorFeatureBits uint16
+}
+
+type systemInfo struct {
+ wProcessorArchitecture uint16
+ wReserved uint16
+ dwpageSize uint32
+ lpMinimumApplicationAddress uintptr
+ lpMaximumApplicationAddress uintptr
+ dwActiveProcessorMask uintptr
+ dwNumberOfProcessors uint32
+ dwProcessorType uint32
+ dwAllocationGranularity uint32
+ wProcessorLevel uint16
+ wProcessorRevision uint16
+}
+
+// Memory_info_ex is different between OSes
+type MemoryInfoExStat struct{}
+
+type MemoryMapsStat struct{}
+
+// ioCounters is an equivalent representation of IO_COUNTERS in the Windows API.
+// https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters
+type ioCounters struct {
+ ReadOperationCount uint64
+ WriteOperationCount uint64
+ OtherOperationCount uint64
+ ReadTransferCount uint64
+ WriteTransferCount uint64
+ OtherTransferCount uint64
+}
+
+type processBasicInformation32 struct {
+ Reserved1 uint32
+ PebBaseAddress uint32
+ Reserved2 uint32
+ Reserved3 uint32
+ UniqueProcessId uint32
+ Reserved4 uint32
+}
+
+type processBasicInformation64 struct {
+ Reserved1 uint64
+ PebBaseAddress uint64
+ Reserved2 uint64
+ Reserved3 uint64
+ UniqueProcessId uint64
+ Reserved4 uint64
+}
+
+type processEnvironmentBlock32 struct {
+ Reserved1 [2]uint8
+ BeingDebugged uint8
+ Reserved2 uint8
+ Reserved3 [2]uint32
+ Ldr uint32
+ ProcessParameters uint32
+ // More fields which we don't use so far
+}
+
+type processEnvironmentBlock64 struct {
+ Reserved1 [2]uint8
+ BeingDebugged uint8
+ Reserved2 uint8
+ _ [4]uint8 // padding, since we are 64 bit, the next pointer is 64 bit aligned (when compiling for 32 bit, this is not the case without manual padding)
+ Reserved3 [2]uint64
+ Ldr uint64
+ ProcessParameters uint64
+ // More fields which we don't use so far
+}
+
+type rtlUserProcessParameters32 struct {
+ Reserved1 [16]uint8
+ ConsoleHandle uint32
+ ConsoleFlags uint32
+ StdInputHandle uint32
+ StdOutputHandle uint32
+ StdErrorHandle uint32
+ CurrentDirectoryPathNameLength uint16
+ _ uint16 // Max Length
+ CurrentDirectoryPathAddress uint32
+ CurrentDirectoryHandle uint32
+ DllPathNameLength uint16
+ _ uint16 // Max Length
+ DllPathAddress uint32
+ ImagePathNameLength uint16
+ _ uint16 // Max Length
+ ImagePathAddress uint32
+ CommandLineLength uint16
+ _ uint16 // Max Length
+ CommandLineAddress uint32
+ EnvironmentAddress uint32
+ // More fields which we don't use so far
+}
+
+type rtlUserProcessParameters64 struct {
+ Reserved1 [16]uint8
+ ConsoleHandle uint64
+ ConsoleFlags uint64
+ StdInputHandle uint64
+ StdOutputHandle uint64
+ StdErrorHandle uint64
+ CurrentDirectoryPathNameLength uint16
+ _ uint16 // Max Length
+ _ uint32 // Padding
+ CurrentDirectoryPathAddress uint64
+ CurrentDirectoryHandle uint64
+ DllPathNameLength uint16
+ _ uint16 // Max Length
+ _ uint32 // Padding
+ DllPathAddress uint64
+ ImagePathNameLength uint16
+ _ uint16 // Max Length
+ _ uint32 // Padding
+ ImagePathAddress uint64
+ CommandLineLength uint16
+ _ uint16 // Max Length
+ _ uint32 // Padding
+ CommandLineAddress uint64
+ EnvironmentAddress uint64
+ // More fields which we don't use so far
+}
+
+type winLUID struct {
+ LowPart winDWord
+ HighPart winLong
+}
+
+// LUID_AND_ATTRIBUTES
+type winLUIDAndAttributes struct {
+ Luid winLUID
+ Attributes winDWord
+}
+
+// TOKEN_PRIVILEGES
+type winTokenPrivileges struct {
+ PrivilegeCount winDWord
+ Privileges [1]winLUIDAndAttributes
+}
+
+type (
+ winLong int32
+ winDWord uint32
+)
+
+func init() {
+ var systemInfo systemInfo
+
+ procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
+ processorArchitecture = uint(systemInfo.wProcessorArchitecture)
+
+ // enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119
+ handle, err := syscall.GetCurrentProcess()
+ if err != nil {
+ return
+ }
+
+ var token syscall.Token
+ err = syscall.OpenProcessToken(handle, 0x0028, &token)
+ if err != nil {
+ return
+ }
+ defer token.Close()
+
+ tokenPrivileges := winTokenPrivileges{PrivilegeCount: 1}
+ lpName := syscall.StringToUTF16("SeDebugPrivilege")
+ ret, _, _ := procLookupPrivilegeValue.Call(
+ 0,
+ uintptr(unsafe.Pointer(&lpName[0])),
+ uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)))
+ if ret == 0 {
+ return
+ }
+
+ tokenPrivileges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED
+
+ procAdjustTokenPrivileges.Call(
+ uintptr(token),
+ 0,
+ uintptr(unsafe.Pointer(&tokenPrivileges)),
+ uintptr(unsafe.Sizeof(tokenPrivileges)),
+ 0,
+ 0)
+}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ // inspired by https://gist.github.com/henkman/3083408
+ // and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
+ var ret []int32
+ var read uint32 = 0
+ var psSize uint32 = 1024
+ const dwordSize uint32 = 4
+
+ for {
+ ps := make([]uint32, psSize)
+ if err := windows.EnumProcesses(ps, &read); err != nil {
+ return nil, err
+ }
+ if uint32(len(ps)) == read/dwordSize { // ps buffer was too small to host every results, retry with a bigger one
+ psSize += 1024
+ continue
+ }
+ for _, pid := range ps[:read/dwordSize] {
+ ret = append(ret, int32(pid))
+ }
+ return ret, nil
+
+ }
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+ if pid == 0 { // special case for pid 0 System Idle Process
+ return true, nil
+ }
+ if pid < 0 {
+ return false, fmt.Errorf("invalid pid %v", pid)
+ }
+ if pid%4 != 0 {
+ // OpenProcess will succeed even on non-existing pid here https://devblogs.microsoft.com/oldnewthing/20080606-00/?p=22043
+ // so we list every pid just to be sure and be future-proof
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return false, err
+ }
+ for _, i := range pids {
+ if i == pid {
+ return true, err
+ }
+ }
+ return false, err
+ }
+ h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
+ if err == windows.ERROR_ACCESS_DENIED {
+ return true, nil
+ }
+ if err == windows.ERROR_INVALID_PARAMETER {
+ return false, nil
+ }
+ if err != nil {
+ return false, err
+ }
+ defer windows.CloseHandle(h)
+ event, err := windows.WaitForSingleObject(h, 0)
+ return event == uint32(windows.WAIT_TIMEOUT), err
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ // if cached already, return from cache
+ cachedPpid := p.getPpid()
+ if cachedPpid != 0 {
+ return cachedPpid, nil
+ }
+
+ ppid, _, _, err := getFromSnapProcess(p.Pid)
+ if err != nil {
+ return 0, err
+ }
+
+ // no errors and not cached already, so cache it
+ p.setPpid(ppid)
+
+ return ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ if p.Pid == 0 {
+ return "System Idle Process", nil
+ }
+ if p.Pid == 4 {
+ return "System", nil
+ }
+
+ exe, err := p.ExeWithContext(ctx)
+ if err != nil {
+ return "", fmt.Errorf("could not get Name: %s", err)
+ }
+
+ return filepath.Base(exe), nil
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+ if err != nil {
+ return "", err
+ }
+ defer windows.CloseHandle(c)
+ buf := make([]uint16, syscall.MAX_LONG_PATH)
+ size := uint32(syscall.MAX_LONG_PATH)
+ if err := procQueryFullProcessImageNameW.Find(); err == nil { // Vista+
+ ret, _, err := procQueryFullProcessImageNameW.Call(
+ uintptr(c),
+ uintptr(0),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&size)))
+ if ret == 0 {
+ return "", err
+ }
+ return windows.UTF16ToString(buf[:]), nil
+ }
+ // XP fallback
+ ret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size))
+ if ret == 0 {
+ return "", err
+ }
+ return common.ConvertDOSPath(windows.UTF16ToString(buf[:])), nil
+}
+
+func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
+ cmdline, err := getProcessCommandLine(p.Pid)
+ if err != nil {
+ return "", fmt.Errorf("could not get CommandLine: %s", err)
+ }
+ return cmdline, nil
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ cmdline, err := p.CmdlineWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return strings.Split(cmdline, " "), nil
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ ru, err := getRusage(p.Pid)
+ if err != nil {
+ return 0, fmt.Errorf("could not get CreationDate: %s", err)
+ }
+
+ return ru.CreationTime.Nanoseconds() / 1000000, nil
+}
+
+func (p *Process) CwdWithContext(_ context.Context) (string, error) {
+ h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
+ if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
+ return "", nil
+ }
+ if err != nil {
+ return "", err
+ }
+ defer syscall.CloseHandle(syscall.Handle(h))
+
+ procIs32Bits := is32BitProcess(h)
+
+ if procIs32Bits {
+ userProcParams, err := getUserProcessParams32(h)
+ if err != nil {
+ return "", err
+ }
+ if userProcParams.CurrentDirectoryPathNameLength > 0 {
+ cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))
+ if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
+ return "", errors.New("cannot read current working directory")
+ }
+
+ return convertUTF16ToString(cwd), nil
+ }
+ } else {
+ userProcParams, err := getUserProcessParams64(h)
+ if err != nil {
+ return "", err
+ }
+ if userProcParams.CurrentDirectoryPathNameLength > 0 {
+ cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
+ if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
+ return "", errors.New("cannot read current working directory")
+ }
+
+ return convertUTF16ToString(cwd), nil
+ }
+ }
+
+ // if we reach here, we have no cwd
+ return "", nil
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ return []string{""}, common.ErrNotImplementedError
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+ if err != nil {
+ return "", err
+ }
+ defer windows.CloseHandle(c)
+
+ var token syscall.Token
+ err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)
+ if err != nil {
+ return "", err
+ }
+ defer token.Close()
+ tokenUser, err := token.GetTokenUser()
+ if err != nil {
+ return "", err
+ }
+
+ user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
+ return domain + "\\" + user, err
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+// priorityClasses maps a win32 priority class to its WMI equivalent Win32_Process.Priority
+// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass
+// https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
+var priorityClasses = map[int]int32{
+ 0x00008000: 10, // ABOVE_NORMAL_PRIORITY_CLASS
+ 0x00004000: 6, // BELOW_NORMAL_PRIORITY_CLASS
+ 0x00000080: 13, // HIGH_PRIORITY_CLASS
+ 0x00000040: 4, // IDLE_PRIORITY_CLASS
+ 0x00000020: 8, // NORMAL_PRIORITY_CLASS
+ 0x00000100: 24, // REALTIME_PRIORITY_CLASS
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+ if err != nil {
+ return 0, err
+ }
+ defer windows.CloseHandle(c)
+ ret, _, err := procGetPriorityClass.Call(uintptr(c))
+ if ret == 0 {
+ return 0, err
+ }
+ priority, ok := priorityClasses[int(ret)]
+ if !ok {
+ return 0, fmt.Errorf("unknown priority class %v", ret)
+ }
+ return priority, nil
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+ if err != nil {
+ return nil, err
+ }
+ defer windows.CloseHandle(c)
+ var ioCounters ioCounters
+ ret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&ioCounters)))
+ if ret == 0 {
+ return nil, err
+ }
+ stats := &IOCountersStat{
+ ReadCount: ioCounters.ReadOperationCount,
+ ReadBytes: ioCounters.ReadTransferCount,
+ WriteCount: ioCounters.WriteOperationCount,
+ WriteBytes: ioCounters.WriteTransferCount,
+ }
+
+ return stats, nil
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+// NumFDsWithContext returns the number of handles for a process on Windows,
+// not the number of file descriptors (FDs).
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ handle, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+ if err != nil {
+ return 0, err
+ }
+ defer windows.CloseHandle(handle)
+
+ var handleCount uint32
+ ret, _, err := procGetProcessHandleCount.Call(uintptr(handle), uintptr(unsafe.Pointer(&handleCount)))
+ if ret == 0 {
+ return 0, err
+ }
+ return int32(handleCount), nil
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ ppid, ret, _, err := getFromSnapProcess(p.Pid)
+ if err != nil {
+ return 0, err
+ }
+
+ // if no errors and not cached already, cache ppid
+ p.parent = ppid
+ if 0 == p.getPpid() {
+ p.setPpid(ppid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ sysTimes, err := getProcessCPUTimes(p.Pid)
+ if err != nil {
+ return nil, err
+ }
+
+ // User and kernel times are represented as a FILETIME structure
+ // which contains a 64-bit value representing the number of
+ // 100-nanosecond intervals since January 1, 1601 (UTC):
+ // http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
+ // To convert it into a float representing the seconds that the
+ // process has executed in user/kernel mode I borrowed the code
+ // below from psutil's _psutil_windows.c, and in turn from Python's
+ // Modules/posixmodule.c
+
+ user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
+ kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
+
+ return &cpu.TimesStat{
+ User: user,
+ System: kernel,
+ }, nil
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ mem, err := getMemoryInfo(p.Pid)
+ if err != nil {
+ return nil, err
+ }
+
+ ret := &MemoryInfoStat{
+ RSS: uint64(mem.WorkingSetSize),
+ VMS: uint64(mem.PagefileUsage),
+ }
+
+ return ret, nil
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+ snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0))
+ if err != nil {
+ return out, err
+ }
+ defer windows.CloseHandle(snap)
+ var pe32 windows.ProcessEntry32
+ pe32.Size = uint32(unsafe.Sizeof(pe32))
+ if err := windows.Process32First(snap, &pe32); err != nil {
+ return out, err
+ }
+ for {
+ if pe32.ParentProcessID == uint32(p.Pid) {
+ p, err := NewProcessWithContext(ctx, int32(pe32.ProcessID))
+ if err == nil {
+ out = append(out, p)
+ }
+ }
+ if err = windows.Process32Next(snap, &pe32); err != nil {
+ break
+ }
+ }
+ return out, nil
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ files := make([]OpenFilesStat, 0)
+ fileExists := make(map[string]bool)
+
+ process, err := windows.OpenProcess(common.ProcessQueryInformation, false, uint32(p.Pid))
+ if err != nil {
+ return nil, err
+ }
+
+ buffer := make([]byte, 1024)
+ var size uint32
+
+ st := common.CallWithExpandingBuffer(
+ func() common.NtStatus {
+ return common.NtQuerySystemInformation(
+ common.SystemExtendedHandleInformationClass,
+ &buffer[0],
+ uint32(len(buffer)),
+ &size,
+ )
+ },
+ &buffer,
+ &size,
+ )
+ if st.IsError() {
+ return nil, st.Error()
+ }
+
+ handlesList := (*common.SystemExtendedHandleInformation)(unsafe.Pointer(&buffer[0]))
+ handles := make([]common.SystemExtendedHandleTableEntryInformation, int(handlesList.NumberOfHandles))
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&handles))
+ hdr.Data = uintptr(unsafe.Pointer(&handlesList.Handles[0]))
+
+ currentProcess, err := windows.GetCurrentProcess()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, handle := range handles {
+ var file uintptr
+ if int32(handle.UniqueProcessId) != p.Pid {
+ continue
+ }
+ if windows.DuplicateHandle(process, windows.Handle(handle.HandleValue), currentProcess, (*windows.Handle)(&file),
+ 0, true, windows.DUPLICATE_SAME_ACCESS) != nil {
+ continue
+ }
+ // release the new handle
+ defer windows.CloseHandle(windows.Handle(file))
+
+ fileType, err := windows.GetFileType(windows.Handle(file))
+ if err != nil || fileType != windows.FILE_TYPE_DISK {
+ continue
+ }
+
+ var fileName string
+ ch := make(chan struct{})
+
+ go func() {
+ var buf [syscall.MAX_LONG_PATH]uint16
+ n, err := windows.GetFinalPathNameByHandle(windows.Handle(file), &buf[0], syscall.MAX_LONG_PATH, 0)
+ if err != nil {
+ return
+ }
+
+ fileName = string(utf16.Decode(buf[:n]))
+ ch <- struct{}{}
+ }()
+
+ select {
+ case <-time.NewTimer(100 * time.Millisecond).C:
+ continue
+ case <-ch:
+ fileInfo, err := os.Stat(fileName)
+ if err != nil || fileInfo.IsDir() {
+ continue
+ }
+
+ if _, exists := fileExists[fileName]; !exists {
+ files = append(files, OpenFilesStat{
+ Path: fileName,
+ Fd: uint64(file),
+ })
+ fileExists[fileName] = true
+ }
+ case <-ctx.Done():
+ return files, ctx.Err()
+ }
+ }
+
+ return files, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
+ if err != nil {
+ return err
+ }
+ defer windows.CloseHandle(c)
+
+ r1, _, _ := procNtSuspendProcess.Call(uintptr(c))
+ if r1 != 0 {
+ // See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
+ return fmt.Errorf("NtStatus='0x%.8X'", r1)
+ }
+
+ return nil
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
+ if err != nil {
+ return err
+ }
+ defer windows.CloseHandle(c)
+
+ r1, _, _ := procNtResumeProcess.Call(uintptr(c))
+ if r1 != 0 {
+ // See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
+ return fmt.Errorf("NtStatus='0x%.8X'", r1)
+ }
+
+ return nil
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ proc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid))
+ if err != nil {
+ return err
+ }
+ err = windows.TerminateProcess(proc, 0)
+ windows.CloseHandle(proc)
+ return err
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ process, err := os.FindProcess(int(p.Pid))
+ if err != nil {
+ return err
+ }
+ defer process.Release()
+ return process.Kill()
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+ envVars, err := getProcessEnvironmentVariables(p.Pid, ctx)
+ if err != nil {
+ return nil, fmt.Errorf("could not get environment variables: %s", err)
+ }
+ return envVars, nil
+}
+
+// retrieve Ppid in a thread-safe manner
+func (p *Process) getPpid() int32 {
+ p.parentMutex.RLock()
+ defer p.parentMutex.RUnlock()
+ return p.parent
+}
+
+// cache Ppid in a thread-safe manner (WINDOWS ONLY)
+// see https://psutil.readthedocs.io/en/latest/#psutil.Process.ppid
+func (p *Process) setPpid(ppid int32) {
+ p.parentMutex.Lock()
+ defer p.parentMutex.Unlock()
+ p.parent = ppid
+}
+
+func getFromSnapProcess(pid int32) (int32, int32, string, error) {
+ snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
+ if err != nil {
+ return 0, 0, "", err
+ }
+ defer windows.CloseHandle(snap)
+ var pe32 windows.ProcessEntry32
+ pe32.Size = uint32(unsafe.Sizeof(pe32))
+ if err = windows.Process32First(snap, &pe32); err != nil {
+ return 0, 0, "", err
+ }
+ for {
+ if pe32.ProcessID == uint32(pid) {
+ szexe := windows.UTF16ToString(pe32.ExeFile[:])
+ return int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil
+ }
+ if err = windows.Process32Next(snap, &pe32); err != nil {
+ break
+ }
+ }
+ return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, fmt.Errorf("could not get Processes %s", err)
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcessWithContext(ctx, pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func getRusage(pid int32) (*windows.Rusage, error) {
+ var CPU windows.Rusage
+
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+ if err != nil {
+ return nil, err
+ }
+ defer windows.CloseHandle(c)
+
+ if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
+ return nil, err
+ }
+
+ return &CPU, nil
+}
+
+func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
+ var mem PROCESS_MEMORY_COUNTERS
+ c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+ if err != nil {
+ return mem, err
+ }
+ defer windows.CloseHandle(c)
+ if err := getProcessMemoryInfo(c, &mem); err != nil {
+ return mem, err
+ }
+
+ return mem, err
+}
+
+func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+type SYSTEM_TIMES struct {
+ CreateTime syscall.Filetime
+ ExitTime syscall.Filetime
+ KernelTime syscall.Filetime
+ UserTime syscall.Filetime
+}
+
+func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
+ var times SYSTEM_TIMES
+
+ h, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+ if err != nil {
+ return times, err
+ }
+ defer windows.CloseHandle(h)
+
+ err = syscall.GetProcessTimes(
+ syscall.Handle(h),
+ &times.CreateTime,
+ &times.ExitTime,
+ &times.KernelTime,
+ &times.UserTime,
+ )
+
+ return times, err
+}
+
+func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {
+ pebAddress, err := queryPebAddress(syscall.Handle(handle), true)
+ if err != nil {
+ return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err)
+ }
+
+ buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
+ if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
+ return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB")
+ }
+ peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
+ userProcessAddress := uint64(peb.ProcessParameters)
+ buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
+ if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
+ return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters")
+ }
+ return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
+}
+
+func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {
+ pebAddress, err := queryPebAddress(syscall.Handle(handle), false)
+ if err != nil {
+ return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err)
+ }
+
+ buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
+ if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
+ return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB")
+ }
+ peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
+ userProcessAddress := peb.ProcessParameters
+ buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
+ if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
+ return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters")
+ }
+ return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
+}
+
+func is32BitProcess(h windows.Handle) bool {
+ const (
+ PROCESSOR_ARCHITECTURE_INTEL = 0
+ PROCESSOR_ARCHITECTURE_ARM = 5
+ PROCESSOR_ARCHITECTURE_ARM64 = 12
+ PROCESSOR_ARCHITECTURE_IA64 = 6
+ PROCESSOR_ARCHITECTURE_AMD64 = 9
+ )
+
+ var procIs32Bits bool
+ switch processorArchitecture {
+ case PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_ARCHITECTURE_ARM:
+ procIs32Bits = true
+ case PROCESSOR_ARCHITECTURE_ARM64, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_AMD64:
+ var wow64 uint
+
+ ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+ uintptr(h),
+ uintptr(common.ProcessWow64Information),
+ uintptr(unsafe.Pointer(&wow64)),
+ uintptr(unsafe.Sizeof(wow64)),
+ uintptr(0),
+ )
+ if int(ret) >= 0 {
+ if wow64 != 0 {
+ procIs32Bits = true
+ }
+ } else {
+ // if the OS does not support the call, we fallback into the bitness of the app
+ if unsafe.Sizeof(wow64) == 4 {
+ procIs32Bits = true
+ }
+ }
+
+ default:
+ // for other unknown platforms, we rely on process platform
+ if unsafe.Sizeof(processorArchitecture) == 8 {
+ procIs32Bits = false
+ } else {
+ procIs32Bits = true
+ }
+ }
+ return procIs32Bits
+}
+
+func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) {
+ h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
+ if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CloseHandle(syscall.Handle(h))
+
+ procIs32Bits := is32BitProcess(h)
+
+ var processParameterBlockAddress uint64
+
+ if procIs32Bits {
+ peb, err := getUserProcessParams32(h)
+ if err != nil {
+ return nil, err
+ }
+ processParameterBlockAddress = uint64(peb.EnvironmentAddress)
+ } else {
+ peb, err := getUserProcessParams64(h)
+ if err != nil {
+ return nil, err
+ }
+ processParameterBlockAddress = peb.EnvironmentAddress
+ }
+ envvarScanner := bufio.NewScanner(&processReader{
+ processHandle: h,
+ is32BitProcess: procIs32Bits,
+ offset: processParameterBlockAddress,
+ })
+ envvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+ // Check for UTF-16 zero character
+ for i := 0; i < len(data)-1; i += 2 {
+ if data[i] == 0 && data[i+1] == 0 {
+ return i + 2, data[0:i], nil
+ }
+ }
+ if atEOF {
+ return len(data), data, nil
+ }
+ // Request more data
+ return 0, nil, nil
+ })
+ var envVars []string
+ for envvarScanner.Scan() {
+ entry := envvarScanner.Bytes()
+ if len(entry) == 0 {
+ break // Block is finished
+ }
+ envVars = append(envVars, convertUTF16ToString(entry))
+ select {
+ case <-ctx.Done():
+ break
+ default:
+ continue
+ }
+ }
+ if err := envvarScanner.Err(); err != nil {
+ return nil, err
+ }
+ return envVars, nil
+}
+
+type processReader struct {
+ processHandle windows.Handle
+ is32BitProcess bool
+ offset uint64
+}
+
+func (p *processReader) Read(buf []byte) (int, error) {
+ processMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf)))
+ if len(processMemory) == 0 {
+ return 0, io.EOF
+ }
+ copy(buf, processMemory)
+ p.offset += uint64(len(processMemory))
+ return len(processMemory), nil
+}
+
+func getProcessCommandLine(pid int32) (string, error) {
+ h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
+ if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
+ return "", nil
+ }
+ if err != nil {
+ return "", err
+ }
+ defer syscall.CloseHandle(syscall.Handle(h))
+
+ procIs32Bits := is32BitProcess(h)
+
+ if procIs32Bits {
+ userProcParams, err := getUserProcessParams32(h)
+ if err != nil {
+ return "", err
+ }
+ if userProcParams.CommandLineLength > 0 {
+ cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength))
+ if len(cmdLine) != int(userProcParams.CommandLineLength) {
+ return "", errors.New("cannot read cmdline")
+ }
+
+ return convertUTF16ToString(cmdLine), nil
+ }
+ } else {
+ userProcParams, err := getUserProcessParams64(h)
+ if err != nil {
+ return "", err
+ }
+ if userProcParams.CommandLineLength > 0 {
+ cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
+ if len(cmdLine) != int(userProcParams.CommandLineLength) {
+ return "", errors.New("cannot read cmdline")
+ }
+
+ return convertUTF16ToString(cmdLine), nil
+ }
+ }
+
+ // if we reach here, we have no command line
+ return "", nil
+}
+
+func convertUTF16ToString(src []byte) string {
+ srcLen := len(src) / 2
+
+ codePoints := make([]uint16, srcLen)
+
+ srcIdx := 0
+ for i := 0; i < srcLen; i++ {
+ codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8
+ srcIdx += 2
+ }
+ return syscall.UTF16ToString(codePoints)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go
new file mode 100644
index 0000000..2b231c7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build (windows && 386) || (windows && arm)
+
+package process
+
+import (
+ "errors"
+ "syscall"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+type PROCESS_MEMORY_COUNTERS struct {
+ CB uint32
+ PageFaultCount uint32
+ PeakWorkingSetSize uint32
+ WorkingSetSize uint32
+ QuotaPeakPagedPoolUsage uint32
+ QuotaPagedPoolUsage uint32
+ QuotaPeakNonPagedPoolUsage uint32
+ QuotaNonPagedPoolUsage uint32
+ PagefileUsage uint32
+ PeakPagefileUsage uint32
+}
+
+func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {
+ if is32BitProcess {
+ // we are on a 32-bit process reading an external 32-bit process
+ var info processBasicInformation32
+
+ ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+ uintptr(procHandle),
+ uintptr(common.ProcessBasicInformation),
+ uintptr(unsafe.Pointer(&info)),
+ uintptr(unsafe.Sizeof(info)),
+ uintptr(0),
+ )
+ if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+ return uint64(info.PebBaseAddress), nil
+ } else {
+ return 0, windows.NTStatus(ret)
+ }
+ } else {
+ // we are on a 32-bit process reading an external 64-bit process
+ if common.ProcNtWow64QueryInformationProcess64.Find() == nil { // avoid panic
+ var info processBasicInformation64
+
+ ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call(
+ uintptr(procHandle),
+ uintptr(common.ProcessBasicInformation),
+ uintptr(unsafe.Pointer(&info)),
+ uintptr(unsafe.Sizeof(info)),
+ uintptr(0),
+ )
+ if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+ return info.PebBaseAddress, nil
+ } else {
+ return 0, windows.NTStatus(ret)
+ }
+ } else {
+ return 0, errors.New("can't find API to query 64 bit process from 32 bit")
+ }
+ }
+}
+
+func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte {
+ if is32BitProcess {
+ var read uint
+
+ buffer := make([]byte, size)
+
+ ret, _, _ := common.ProcNtReadVirtualMemory.Call(
+ uintptr(h),
+ uintptr(address),
+ uintptr(unsafe.Pointer(&buffer[0])),
+ uintptr(size),
+ uintptr(unsafe.Pointer(&read)),
+ )
+ if int(ret) >= 0 && read > 0 {
+ return buffer[:read]
+ }
+ } else {
+ // reading a 64-bit process from a 32-bit one
+ if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { // avoid panic
+ var read uint64
+
+ buffer := make([]byte, size)
+
+ ret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call(
+ uintptr(h),
+ uintptr(address&0xFFFFFFFF), // the call expects a 64-bit value
+ uintptr(address>>32),
+ uintptr(unsafe.Pointer(&buffer[0])),
+ uintptr(size), // the call expects a 64-bit value
+ uintptr(0), // but size is 32-bit so pass zero as the high dword
+ uintptr(unsafe.Pointer(&read)),
+ )
+ if int(ret) >= 0 && read > 0 {
+ return buffer[:uint(read)]
+ }
+ }
+ }
+
+ // if we reach here, an error happened
+ return nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go
new file mode 100644
index 0000000..befe521
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build (windows && amd64) || (windows && arm64)
+
+package process
+
+import (
+ "syscall"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/v4/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+type PROCESS_MEMORY_COUNTERS struct {
+ CB uint32
+ PageFaultCount uint32
+ PeakWorkingSetSize uint64
+ WorkingSetSize uint64
+ QuotaPeakPagedPoolUsage uint64
+ QuotaPagedPoolUsage uint64
+ QuotaPeakNonPagedPoolUsage uint64
+ QuotaNonPagedPoolUsage uint64
+ PagefileUsage uint64
+ PeakPagefileUsage uint64
+}
+
+func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {
+ if is32BitProcess {
+ // we are on a 64-bit process reading an external 32-bit process
+ var wow64 uint
+
+ ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+ uintptr(procHandle),
+ uintptr(common.ProcessWow64Information),
+ uintptr(unsafe.Pointer(&wow64)),
+ uintptr(unsafe.Sizeof(wow64)),
+ uintptr(0),
+ )
+ if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+ return uint64(wow64), nil
+ } else {
+ return 0, windows.NTStatus(ret)
+ }
+ } else {
+ // we are on a 64-bit process reading an external 64-bit process
+ var info processBasicInformation64
+
+ ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+ uintptr(procHandle),
+ uintptr(common.ProcessBasicInformation),
+ uintptr(unsafe.Pointer(&info)),
+ uintptr(unsafe.Sizeof(info)),
+ uintptr(0),
+ )
+ if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+ return info.PebBaseAddress, nil
+ } else {
+ return 0, windows.NTStatus(ret)
+ }
+ }
+}
+
+func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte {
+ var read uint
+
+ buffer := make([]byte, size)
+
+ ret, _, _ := common.ProcNtReadVirtualMemory.Call(
+ uintptr(procHandle),
+ uintptr(address),
+ uintptr(unsafe.Pointer(&buffer[0])),
+ uintptr(size),
+ uintptr(unsafe.Pointer(&read)),
+ )
+ if int(ret) >= 0 && read > 0 {
+ return buffer[:read]
+ }
+ return nil
+}