summaryrefslogtreecommitdiff
path: root/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go')
-rw-r--r--vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go397
1 files changed, 397 insertions, 0 deletions
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
new file mode 100644
index 0000000..5e8a9e0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ cpu "github.com/shirou/gopsutil/v4/cpu"
+ "github.com/shirou/gopsutil/v4/internal/common"
+ mem "github.com/shirou/gopsutil/v4/mem"
+ net "github.com/shirou/gopsutil/v4/net"
+ "golang.org/x/sys/unix"
+)
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return ret, nil
+ }
+
+ for _, p := range procs {
+ ret = append(ret, p.Pid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+ name := common.IntToString(k.Comm[:])
+
+ if len(name) >= 15 {
+ cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ if len(cmdlineSlice) > 0 {
+ extendedName := filepath.Base(cmdlineSlice[0])
+ if strings.HasPrefix(extendedName, p.name) {
+ name = extendedName
+ }
+ }
+ }
+
+ return name, nil
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProcCwd, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+ return common.ByteToString(buf), nil
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+
+ /* From man sysctl(2):
+ The buffer pointed to by oldp is filled with an array of char
+ pointers followed by the strings themselves. The last char
+ pointer is a NULL pointer. */
+ var strParts []string
+ r := bytes.NewReader(buf)
+ baseAddr := uintptr(unsafe.Pointer(&buf[0]))
+ for {
+ argvp, err := readPtr(r)
+ if err != nil {
+ return nil, err
+ }
+ if argvp == 0 { // check for a NULL pointer
+ break
+ }
+ offset := argvp - baseAddr
+ length := uintptr(bytes.IndexByte(buf[offset:], 0))
+ str := string(buf[offset : offset+length])
+ strParts = append(strParts, str)
+ }
+
+ return strParts, nil
+}
+
+// readPtr reads a pointer data from a given reader. WARNING: only little
+// endian architectures are supported.
+func readPtr(r io.Reader) (uintptr, error) {
+ switch sizeofPtr {
+ case 4:
+ var p uint32
+ if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+ return 0, err
+ }
+ return uintptr(p), nil
+ case 8:
+ var p uint64
+ if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+ return 0, err
+ }
+ return uintptr(p), nil
+ default:
+ return 0, fmt.Errorf("unsupported pointer size")
+ }
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ argv, err := p.CmdlineSliceWithContext(ctx)
+ if err != nil {
+ return "", err
+ }
+ return strings.Join(argv, " "), nil
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return []string{""}, err
+ }
+ var s string
+ switch k.Stat {
+ case SIDL:
+ case SRUN:
+ case SONPROC:
+ s = Running
+ case SSLEEP:
+ s = Sleep
+ case SSTOP:
+ s = Stop
+ case SDEAD:
+ s = Zombie
+ }
+
+ return []string{s}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ uids := make([]uint32, 0, 3)
+
+ uids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))
+
+ return uids, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]uint32, 0, 3)
+ gids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))
+
+ return gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ groups := make([]uint32, k.Ngroups)
+ for i := int16(0); i < k.Ngroups; i++ {
+ groups[i] = uint32(k.Groups[i])
+ }
+
+ return groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Tdev)
+
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Nice), nil
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &IOCountersStat{
+ ReadCount: uint64(k.Uru_inblock),
+ WriteCount: uint64(k.Uru_oublock),
+ }, nil
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ /* not supported, just return 1 */
+ return 1, nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
+ System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
+ }, nil
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ pageSize, err := mem.GetPageSizeWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return &MemoryInfoStat{
+ RSS: uint64(k.Vm_rssize) * pageSize,
+ VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
+ uint64(k.Vm_ssize),
+ }, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ procs, err := ProcessesWithContext(ctx)
+ if err != nil {
+ return nil, nil
+ }
+ ret := make([]*Process, 0, len(procs))
+ for _, proc := range procs {
+ ppid, err := proc.PpidWithContext(ctx)
+ if err != nil {
+ continue
+ }
+ if ppid == p.Pid {
+ ret = append(ret, proc)
+ }
+ }
+ sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+ return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ results := []*Process{}
+
+ buf, length, err := callKernProcSyscall(KernProcAll, 0)
+ if err != nil {
+ return results, err
+ }
+
+ // get kinfo_proc size
+ count := int(length / uint64(sizeOfKinfoProc))
+
+ // parse buf to procs
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+ k, err := parseKinfoProc(b)
+ if err != nil {
+ continue
+ }
+ p, err := NewProcessWithContext(ctx, int32(k.Pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+
+ return results, nil
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+ buf, length, err := callKernProcSyscall(KernProcPID, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ if length != sizeOfKinfoProc {
+ return nil, errors.New("unexpected size of KinfoProc")
+ }
+
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &k, nil
+}
+
+func callKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
+ mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return nil, length, err
+ }
+
+ count := int32(length / uint64(sizeOfKinfoProc))
+ mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
+ mibptr = unsafe.Pointer(&mib[0])
+ miblen = uint64(len(mib))
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}