Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+645
View File
@@ -0,0 +1,645 @@
// SPDX-License-Identifier: BSD-3-Clause
package process
import (
"context"
"encoding/json"
"errors"
"regexp"
"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{}
strictIntPtrn = regexp.MustCompile(`^\d+$`)
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
deltaProc := (t2.User - t1.User) + (t2.System - t1.System)
if deltaProc <= 0 {
return 0
}
overallPercent := ((deltaProc / delta) * 100) * float64(numcpu)
return overallPercent
}
// 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) {
createTime, 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, createTime*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.
//
// On Windows, this assumes the command line is encoded according to the convention accepted by
// [golang.org/x/sys/windows.CmdlineToArgv] (the most common convention). If this is not suitable,
// you should instead use [Process.Cmdline] and parse the command line according to your specific
// requirements.
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
}
}
+72
View File
@@ -0,0 +1,72 @@
// 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 (*Process) TgidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
return nil, common.ErrNotImplementedError
}
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := binary.Read(br, binary.LittleEndian, &k)
return k, err
}
+523
View File
@@ -0,0 +1,523 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build darwin
package process
import (
"bytes"
"context"
"encoding/binary"
"errors"
"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 { //nolint:revive //FIXME
Pad uint64
}
func pidsWithContext(_ context.Context) ([]int32, error) {
var ret []int32
kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
if err != nil {
return ret, err
}
for i := range kprocs {
proc := &kprocs[i]
ret = append(ret, int32(proc.Proc.P_pid))
}
return ret, nil
}
func (p *Process) PpidWithContext(_ 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 cmdName != "" {
extendedName := filepath.Base(cmdName)
if strings.HasPrefix(extendedName, p.name) {
name = extendedName
}
}
}
return name, nil
}
func (p *Process) createTimeWithContext(_ 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(_ 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(_ 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.Ucred.Groups[0]), uint32(k.Eproc.Pcred.P_svgid))
return gids, nil
}
func (*Process) GroupsWithContext(_ 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 (*Process) TerminalWithContext(_ 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(_ context.Context) (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Proc.P_nice), nil
}
func (*Process) IOCountersWithContext(_ 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 split 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, nameOption bool) ([][]string, error) {
var cmd []string
switch {
case pid == 0: // will get from all processes.
cmd = []string{"-ax", "-o", arg}
case threadOption:
cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
default:
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
}
type dlFuncs struct {
lib *common.SystemLib
}
func loadProcFuncs() (*dlFuncs, error) {
lib, err := common.NewSystemLib()
if err != nil {
return nil, err
}
return &dlFuncs{lib}, err
}
func (f *dlFuncs) getTimeScaleToNanoSeconds() float64 {
var timeBaseInfo common.MachTimeBaseInfo
f.lib.MachTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo)))
return float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom)
}
func (f *dlFuncs) Close() {
f.lib.Close()
}
func (p *Process) ExeWithContext(_ context.Context) (string, error) {
funcs, err := loadProcFuncs()
if err != nil {
return "", err
}
defer funcs.Close()
buf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE)
ret := funcs.lib.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
}
// 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(_ context.Context) (string, error) {
funcs, err := loadProcFuncs()
if err != nil {
return "", err
}
defer funcs.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 := funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize)
errno, _ := funcs.lib.Dlsym("errno")
err = *(**unix.Errno)(unsafe.Pointer(&errno))
if errors.Is(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((*byte)(unsafe.Pointer(&vpi.Cdir.Path[0]))), nil
}
func procArgs(pid int32) ([]byte, int, error) {
procargs, err := unix.SysctlRaw("kern.procargs2", int(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(_ context.Context) ([]string, error) {
return p.cmdlineSlice()
}
func (p *Process) cmdlineSlice() ([]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 argStr != "" {
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(_ context.Context) (string, error) {
r, err := p.cmdlineSlice()
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(_ context.Context) (int32, error) {
funcs, err := loadProcFuncs()
if err != nil {
return 0, err
}
defer funcs.Close()
var ti ProcTaskInfo
funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
return int32(ti.Threadnum), nil
}
func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
funcs, err := loadProcFuncs()
if err != nil {
return nil, err
}
defer funcs.Close()
var ti ProcTaskInfo
funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
timescaleToNanoSeconds := funcs.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(_ context.Context) (*MemoryInfoStat, error) {
funcs, err := loadProcFuncs()
if err != nil {
return nil, err
}
defer funcs.Close()
var ti ProcTaskInfo
funcs.lib.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),
}
return ret, nil
}
// procFDInfo represents a file descriptor entry from sys/proc_info.h
type procFDInfo struct {
ProcFd int32
ProcFdtype uint32
}
// NumFDsWithContext returns the number of file descriptors used by the process.
// It uses proc_pidinfo with PROC_PIDLISTFDS to query the kernel for the count
// of open file descriptors. The method makes a single syscall and calculates
// the count from the buffer size returned by the kernel.
func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {
funcs, err := loadProcFuncs()
if err != nil {
return 0, err
}
defer funcs.Close()
// First call: get required buffer size
bufferSize := funcs.lib.ProcPidInfo(
p.Pid,
common.PROC_PIDLISTFDS,
0,
0, // NULL buffer
0, // 0 size
)
if bufferSize <= 0 {
return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", bufferSize)
}
// Allocate buffer of the required size
const sizeofProcFDInfo = int32(unsafe.Sizeof(procFDInfo{}))
numEntries := bufferSize / sizeofProcFDInfo
buf := make([]procFDInfo, numEntries)
// Second call: get actual data
ret := funcs.lib.ProcPidInfo(
p.Pid,
common.PROC_PIDLISTFDS,
0,
uintptr(unsafe.Pointer(&buf[0])), // Real buffer
bufferSize, // Size from first call
)
if ret <= 0 {
return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
}
// Calculate actual number of FDs returned
numFDs := ret / sizeofProcFDInfo
return numFDs, nil
}
@@ -0,0 +1,303 @@
// 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 vinfoStat struct {
Dev uint32
Mode uint16
Nlink uint16
Ino uint64
Uid uint32
Gid uint32
Atime int64
Atimensec int64
Mtime int64
Mtimensec int64
Ctime int64
Ctimensec int64
Birthtime int64
Birthtimensec int64
Size int64
Blocks int64
Blksize int32
Flags uint32
Gen uint32
Rdev uint32
Qspare [2]int64
}
type fsid struct {
Val [2]int32
}
type vnodeInfo struct {
Stat vinfoStat
Type int32
Pad int32
Fsid fsid
}
type vnodeInfoPath struct {
Vi vnodeInfo
Path [1024]int8
}
type vnodePathInfo struct {
Cdir vnodeInfoPath
Rdir vnodeInfoPath
}
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
}
@@ -0,0 +1,279 @@
// 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 vinfoStat struct {
Dev uint32
Mode uint16
Nlink uint16
Ino uint64
Uid uint32
Gid uint32
Atime int64
Atimensec int64
Mtime int64
Mtimensec int64
Ctime int64
Ctimensec int64
Birthtime int64
Birthtimensec int64
Size int64
Blocks int64
Blksize int32
Flags uint32
Gen uint32
Rdev uint32
Qspare [2]int64
}
type fsid struct {
Val [2]int32
}
type vnodeInfo struct {
Stat vinfoStat
Type int32
Pad int32
Fsid fsid
}
type vnodeInfoPath struct {
Vi vnodeInfo
Path [1024]int8
}
type vnodePathInfo struct {
Cdir vnodeInfoPath
Rdir vnodeInfoPath
}
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
}
+203
View File
@@ -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(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func ProcessesWithContext(_ context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func PidExistsWithContext(_ context.Context, _ int32) (bool, error) {
return false, common.ErrNotImplementedError
}
func (*Process) PpidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) NameWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) TgidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) ExeWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) CmdlineWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) CwdWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
return []string{""}, common.ErrNotImplementedError
}
func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
return false, common.ErrNotImplementedError
}
func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TerminalWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) NiceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {
return common.ErrNotImplementedError
}
func (*Process) SuspendWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) ResumeWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) TerminateWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) KillWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) UsernameWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
return nil, common.ErrNotImplementedError
}
+367
View File
@@ -0,0 +1,367 @@
// 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(_ 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(_ 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 := binary.Read(br, binary.LittleEndian, &k); err != nil {
return "", err
}
cwd := common.IntToString(k.Path[:])
return cwd, nil
}
func (p *Process) ExeWithContext(_ 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(_ 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(_ 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(_ 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(_ 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(_ 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(_ 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(_ 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(_ 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(_ context.Context) (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Nice), nil
}
func (p *Process) IOCountersWithContext(_ 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(_ context.Context) (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return k.Numthreads, nil
}
func (p *Process) TimesWithContext(_ 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(_ 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 := binary.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 (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
File diff suppressed because it is too large Load Diff
+401
View File
@@ -0,0 +1,401 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build openbsd
package process
import (
"bytes"
"context"
"encoding/binary"
"errors"
"io"
"path/filepath"
"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/mem"
"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(_ 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(_ 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 (*Process) ExeWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (p *Process) CmdlineSliceWithContext(_ 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, errors.New("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 (*Process) createTimeWithContext(_ context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) StatusWithContext(_ 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(_ 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(_ 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(_ 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(_ 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(_ context.Context) (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Nice), nil
}
func (p *Process) IOCountersWithContext(_ 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 (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
/* not supported, just return 1 */
return 1, nil
}
func (p *Process) TimesWithContext(_ 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 (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsMaxWithContext(_ context.Context, _ 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 (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
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, 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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
+203
View File
@@ -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(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func ProcessesWithContext(_ context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func PidExistsWithContext(_ context.Context, _ int32) (bool, error) {
return false, common.ErrNotImplementedError
}
func (*Process) PpidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) NameWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) TgidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) ExeWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) CmdlineWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) CwdWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
return []string{""}, common.ErrNotImplementedError
}
func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
return false, common.ErrNotImplementedError
}
func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TerminalWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) NiceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {
return common.ErrNotImplementedError
}
func (*Process) SuspendWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) ResumeWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) TerminateWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) KillWithContext(_ context.Context) error {
return common.ErrNotImplementedError
}
func (*Process) UsernameWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
return nil, common.ErrNotImplementedError
}
+187
View File
@@ -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
devPath := common.HostDev()
d, err := os.Open(devPath)
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, "tty") {
termfiles = append(termfiles, filepath.Join(devPath, devname))
}
}
var ptsnames []string
ptsPath := filepath.Join(devPath, "pts")
ptsd, err := os.Open(ptsPath)
if err != nil {
ptsnames, _ = filepath.Glob(filepath.Join(devPath, "ttyp*"))
if ptsnames == nil {
return nil, err
}
termfiles = append(termfiles, ptsnames...)
} else {
defer ptsd.Close()
ptsnames, err = ptsd.Readdirnames(-1)
if err != nil {
return nil, err
}
for _, ptsname := range ptsnames {
termfiles = append(termfiles, filepath.Join(ptsPath, ptsname))
}
}
for _, name := range termfiles {
stat := unix.Stat_t{}
err = unix.Stat(name, &stat)
if err != nil {
return nil, err
}
rdev := uint64(stat.Rdev)
ret[rdev] = strings.TrimPrefix(name, devPath+string(os.PathSeparator))
}
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(_ 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
}
+304
View File
@@ -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 (*Process) PpidWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) NameWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) TgidWithContext(_ 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 (*Process) createTimeWithContext(_ context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return p.fillFromPathCwdWithContext(ctx)
}
func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
return []string{""}, common.ErrNotImplementedError
}
func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
return false, common.ErrNotImplementedError
}
func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TerminalWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func (*Process) NiceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) NumCtxSwitchesWithContext(_ 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 (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
return nil, common.ErrNotImplementedError
}
func (*Process) EnvironWithContext(_ 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 {
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
}
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 {
if !strictIntPtrn.MatchString(fname) {
continue
}
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
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build (windows && 386) || (windows && arm)
package process
import (
"errors"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
)
type PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME
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
}
return 0, windows.NTStatus(ret)
}
// we are on a 32-bit process reading an external 64-bit process
if common.ProcNtWow64QueryInformationProcess64.Find() != nil {
return 0, errors.New("can't find API to query 64 bit process from 32 bit")
}
// 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
}
return 0, windows.NTStatus(ret)
}
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]
}
// reading a 64-bit process from a 32-bit one
} else 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
}
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build (windows && amd64) || (windows && arm64)
package process
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
)
type PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME
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
}
return 0, windows.NTStatus(ret)
}
// 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
}
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
}