Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:rschmied/gopsutil into rschmied-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
shirou committed Oct 30, 2021
2 parents e032a1c + 9494ebd commit 45a1287
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 26 deletions.
1 change: 1 addition & 0 deletions v3/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var (
invoke common.Invoker = common.Invoke{}
ErrorNoChildren = errors.New("process does not have children")
ErrorProcessNotRunning = errors.New("process does not exist")
ErrorNotPermitted = errors.New("operation not permitted")
)

type Process struct {
Expand Down
5 changes: 0 additions & 5 deletions v3/process/process_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}

func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}

func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
return 0, common.ErrNotImplementedError
}
Expand Down Expand Up @@ -77,4 +73,3 @@ func parseKinfoProc(buf []byte) (KinfoProc, error) {
err := common.Read(br, binary.LittleEndian, &k)
return k, err
}

21 changes: 0 additions & 21 deletions v3/process/process_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,6 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return name, nil
}

func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
if err != nil {
return "", err
}
return strings.Join(r[0], " "), err
}

// cmdNameWithContext returns the command name (including spaces) without any arguments
func (p *Process) cmdNameWithContext(ctx context.Context) ([]string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, true)
Expand All @@ -117,19 +109,6 @@ func (p *Process) cmdNameWithContext(ctx context.Context) ([]string, error) {
return r[0], err
}

// CmdlineSliceWithContext returns the command line arguments of the process as a slice with each
// element being an argument. Because of current deficiencies in the way that the command
// line arguments are found, single arguments that have spaces in the will actually be
// reported as two separate items. In order to do something better CGO would be needed
// to use the native darwin functions.
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
if err != nil {
return nil, err
}
return r[0], err
}

func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
r, err := callPsWithContext(ctx, "etime", p.Pid, false, false)
if err != nil {
Expand Down
109 changes: 109 additions & 0 deletions v3/process/process_darwin_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,39 @@ package process

// #include <stdlib.h>
// #include <libproc.h>
// #include <string.h>
// #include <sys/errno.h>
// #include <sys/proc_info.h>
// #include <sys/sysctl.h>
import "C"
import (
"bytes"
"context"
"fmt"
"strings"
"syscall"
"unsafe"
)

var argMax int

func init() {
argMax = getArgMax()
}

func getArgMax() int {
var (
mib = [...]C.int{C.CTL_KERN, C.KERN_ARGMAX}
argmax C.int
size C.size_t = C.ulong(unsafe.Sizeof(argmax))
)
retval := C.sysctl(&mib[0], 2, unsafe.Pointer(&argmax), &size, C.NULL, 0)
if retval == 0 {
return int(argmax)
}
return 0
}

func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
var c C.char // need a var for unsafe.Sizeof need a var
const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c)
Expand All @@ -28,3 +54,86 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {

return C.GoString(buffer), 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(ctx context.Context) (string, error) {
const vpiSize = C.sizeof_struct_proc_vnodepathinfo
vpi := (*C.struct_proc_vnodepathinfo)(C.malloc(vpiSize))
defer C.free(unsafe.Pointer(vpi))
ret, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDVNODEPATHINFO, 0, unsafe.Pointer(vpi), vpiSize)
if err != nil {
// fmt.Printf("ret: %d %T\n", ret, err)
if err == syscall.EPERM {
return "", ErrorNotPermitted
}
return "", err
}
if ret <= 0 {
return "", fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
}
if ret != C.sizeof_struct_proc_vnodepathinfo {
return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret)
}
return C.GoString(&vpi.pvi_cdir.vip_path[0]), err
}

func procArgs(pid int32) (*[]byte, int, error) {
var (
mib = [...]C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
size C.size_t = C.ulong(argMax)
nargs C.int
result []byte
)
procargs := (*C.char)(C.malloc(C.ulong(argMax)))
defer C.free(unsafe.Pointer(procargs))
retval := C.sysctl(&mib[0], 3, unsafe.Pointer(procargs), &size, C.NULL, 0)
if retval == 0 {
C.memcpy(unsafe.Pointer(&nargs), unsafe.Pointer(procargs), C.sizeof_int)
result = C.GoBytes(unsafe.Pointer(procargs), C.int(size))
// fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result))
return &result, int(nargs), nil
}
return nil, 0, fmt.Errorf("error: %d", retval)
}

func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]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)[C.sizeof_int:], []byte{0})
var argStr string
// The first element is the actual binary/command path.
// command := args[0]
var argSlice []string
// var envSlice []string
// All other, non-zero elements are arguments. The first "nargs" elements
// are the arguments. Everything else in the slice is then the environment
// of the process.
for _, arg := range args[1:] {
argStr = string(arg[:])
if len(argStr) > 0 {
if nargs > 0 {
argSlice = append(argSlice, argStr)
nargs--
continue
}
break
// envSlice = append(envSlice, argStr)
}
}
return argSlice, err
}

func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
r, err := p.CmdlineSliceWithContext(ctx)
if err != nil {
return "", err
}
return strings.Join(r, " "), err
}
27 changes: 27 additions & 0 deletions v3/process/process_darwin_nocgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ import (
"os/exec"
"strconv"
"strings"

"github.com/shirou/gopsutil/v3/internal/common"
)

func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}

func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
lsof_bin, err := exec.LookPath("lsof")
if err != nil {
Expand All @@ -32,3 +38,24 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
}
return "", fmt.Errorf("missing txt data returned by lsof")
}

func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
if err != nil {
return "", err
}
return strings.Join(r[0], " "), err
}

// CmdlineSliceWithContext returns the command line arguments of the process as a slice with each
// element being an argument. Because of current deficiencies in the way that the command
// line arguments are found, single arguments that have spaces in the will actually be
// reported as two separate items. In order to do something better CGO would be needed
// to use the native darwin functions.
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
if err != nil {
return nil, err
}
return r[0], err
}
4 changes: 4 additions & 0 deletions v3/process/process_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return name, nil
}

func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}

func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
Expand Down
4 changes: 4 additions & 0 deletions v3/process/process_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
return name, nil
}

func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}

func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
Expand Down

0 comments on commit 45a1287

Please sign in to comment.