Skip to content

Commit 61f064f

Browse files
committed
Merge branch 'rschmied-dev'
2 parents e032a1c + 45a1287 commit 61f064f

7 files changed

+145
-26
lines changed

v3/process/process.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var (
1919
invoke common.Invoker = common.Invoke{}
2020
ErrorNoChildren = errors.New("process does not have children")
2121
ErrorProcessNotRunning = errors.New("process does not exist")
22+
ErrorNotPermitted = errors.New("operation not permitted")
2223
)
2324

2425
type Process struct {

v3/process/process_bsd.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
1919
return 0, common.ErrNotImplementedError
2020
}
2121

22-
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
23-
return "", common.ErrNotImplementedError
24-
}
25-
2622
func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
2723
return 0, common.ErrNotImplementedError
2824
}
@@ -77,4 +73,3 @@ func parseKinfoProc(buf []byte) (KinfoProc, error) {
7773
err := common.Read(br, binary.LittleEndian, &k)
7874
return k, err
7975
}
80-

v3/process/process_darwin.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,6 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
100100
return name, nil
101101
}
102102

103-
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
104-
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
105-
if err != nil {
106-
return "", err
107-
}
108-
return strings.Join(r[0], " "), err
109-
}
110-
111103
// cmdNameWithContext returns the command name (including spaces) without any arguments
112104
func (p *Process) cmdNameWithContext(ctx context.Context) ([]string, error) {
113105
r, err := callPsWithContext(ctx, "command", p.Pid, false, true)
@@ -117,19 +109,6 @@ func (p *Process) cmdNameWithContext(ctx context.Context) ([]string, error) {
117109
return r[0], err
118110
}
119111

120-
// CmdlineSliceWithContext returns the command line arguments of the process as a slice with each
121-
// element being an argument. Because of current deficiencies in the way that the command
122-
// line arguments are found, single arguments that have spaces in the will actually be
123-
// reported as two separate items. In order to do something better CGO would be needed
124-
// to use the native darwin functions.
125-
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
126-
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
127-
if err != nil {
128-
return nil, err
129-
}
130-
return r[0], err
131-
}
132-
133112
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
134113
r, err := callPsWithContext(ctx, "etime", p.Pid, false, false)
135114
if err != nil {

v3/process/process_darwin_cgo.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,39 @@ package process
55

66
// #include <stdlib.h>
77
// #include <libproc.h>
8+
// #include <string.h>
9+
// #include <sys/errno.h>
10+
// #include <sys/proc_info.h>
11+
// #include <sys/sysctl.h>
812
import "C"
913
import (
14+
"bytes"
1015
"context"
1116
"fmt"
17+
"strings"
18+
"syscall"
1219
"unsafe"
1320
)
1421

22+
var argMax int
23+
24+
func init() {
25+
argMax = getArgMax()
26+
}
27+
28+
func getArgMax() int {
29+
var (
30+
mib = [...]C.int{C.CTL_KERN, C.KERN_ARGMAX}
31+
argmax C.int
32+
size C.size_t = C.ulong(unsafe.Sizeof(argmax))
33+
)
34+
retval := C.sysctl(&mib[0], 2, unsafe.Pointer(&argmax), &size, C.NULL, 0)
35+
if retval == 0 {
36+
return int(argmax)
37+
}
38+
return 0
39+
}
40+
1541
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
1642
var c C.char // need a var for unsafe.Sizeof need a var
1743
const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c)
@@ -28,3 +54,86 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
2854

2955
return C.GoString(buffer), nil
3056
}
57+
58+
// CwdWithContext retrieves the Current Working Directory for the given process.
59+
// It uses the proc_pidinfo from libproc and will only work for processes the
60+
// EUID can access. Otherwise "operation not permitted" will be returned as the
61+
// error.
62+
// Note: This might also work for other *BSD OSs.
63+
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
64+
const vpiSize = C.sizeof_struct_proc_vnodepathinfo
65+
vpi := (*C.struct_proc_vnodepathinfo)(C.malloc(vpiSize))
66+
defer C.free(unsafe.Pointer(vpi))
67+
ret, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDVNODEPATHINFO, 0, unsafe.Pointer(vpi), vpiSize)
68+
if err != nil {
69+
// fmt.Printf("ret: %d %T\n", ret, err)
70+
if err == syscall.EPERM {
71+
return "", ErrorNotPermitted
72+
}
73+
return "", err
74+
}
75+
if ret <= 0 {
76+
return "", fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
77+
}
78+
if ret != C.sizeof_struct_proc_vnodepathinfo {
79+
return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret)
80+
}
81+
return C.GoString(&vpi.pvi_cdir.vip_path[0]), err
82+
}
83+
84+
func procArgs(pid int32) (*[]byte, int, error) {
85+
var (
86+
mib = [...]C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
87+
size C.size_t = C.ulong(argMax)
88+
nargs C.int
89+
result []byte
90+
)
91+
procargs := (*C.char)(C.malloc(C.ulong(argMax)))
92+
defer C.free(unsafe.Pointer(procargs))
93+
retval := C.sysctl(&mib[0], 3, unsafe.Pointer(procargs), &size, C.NULL, 0)
94+
if retval == 0 {
95+
C.memcpy(unsafe.Pointer(&nargs), unsafe.Pointer(procargs), C.sizeof_int)
96+
result = C.GoBytes(unsafe.Pointer(procargs), C.int(size))
97+
// fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result))
98+
return &result, int(nargs), nil
99+
}
100+
return nil, 0, fmt.Errorf("error: %d", retval)
101+
}
102+
103+
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
104+
pargs, nargs, err := procArgs(p.Pid)
105+
if err != nil {
106+
return nil, err
107+
}
108+
// The first bytes hold the nargs int, skip it.
109+
args := bytes.Split((*pargs)[C.sizeof_int:], []byte{0})
110+
var argStr string
111+
// The first element is the actual binary/command path.
112+
// command := args[0]
113+
var argSlice []string
114+
// var envSlice []string
115+
// All other, non-zero elements are arguments. The first "nargs" elements
116+
// are the arguments. Everything else in the slice is then the environment
117+
// of the process.
118+
for _, arg := range args[1:] {
119+
argStr = string(arg[:])
120+
if len(argStr) > 0 {
121+
if nargs > 0 {
122+
argSlice = append(argSlice, argStr)
123+
nargs--
124+
continue
125+
}
126+
break
127+
// envSlice = append(envSlice, argStr)
128+
}
129+
}
130+
return argSlice, err
131+
}
132+
133+
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
134+
r, err := p.CmdlineSliceWithContext(ctx)
135+
if err != nil {
136+
return "", err
137+
}
138+
return strings.Join(r, " "), err
139+
}

v3/process/process_darwin_nocgo.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ import (
99
"os/exec"
1010
"strconv"
1111
"strings"
12+
13+
"github.com/shirou/gopsutil/v3/internal/common"
1214
)
1315

16+
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
17+
return "", common.ErrNotImplementedError
18+
}
19+
1420
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
1521
lsof_bin, err := exec.LookPath("lsof")
1622
if err != nil {
@@ -32,3 +38,24 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
3238
}
3339
return "", fmt.Errorf("missing txt data returned by lsof")
3440
}
41+
42+
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
43+
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
44+
if err != nil {
45+
return "", err
46+
}
47+
return strings.Join(r[0], " "), err
48+
}
49+
50+
// CmdlineSliceWithContext returns the command line arguments of the process as a slice with each
51+
// element being an argument. Because of current deficiencies in the way that the command
52+
// line arguments are found, single arguments that have spaces in the will actually be
53+
// reported as two separate items. In order to do something better CGO would be needed
54+
// to use the native darwin functions.
55+
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
56+
r, err := callPsWithContext(ctx, "command", p.Pid, false, false)
57+
if err != nil {
58+
return nil, err
59+
}
60+
return r[0], err
61+
}

v3/process/process_freebsd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
6464
return name, nil
6565
}
6666

67+
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
68+
return "", common.ErrNotImplementedError
69+
}
70+
6771
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
6872
return "", common.ErrNotImplementedError
6973
}

v3/process/process_openbsd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
6969
return name, nil
7070
}
7171

72+
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
73+
return "", common.ErrNotImplementedError
74+
}
75+
7276
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
7377
return "", common.ErrNotImplementedError
7478
}

0 commit comments

Comments
 (0)