summaryrefslogtreecommitdiff
path: root/vendor/github.com/shirou/gopsutil/v4/process
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/shirou/gopsutil/v4/process')
-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
24 files changed, 7821 insertions, 0 deletions
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
+}