mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-24 13:48:56 +08:00
Remove CGO bits from process_openbsd.go (also v3)
Prior to this commit CGO was used in OpenBSD implementation of Process.CmdlineSliceWithContext() for parsing the "kern.proc.args" sysctl output. It requires some pointer arithmetics and raw pointer dereferencing. Having CGO in the "process" module prevents it from being go vet'ted on any platform other than OpenBSD. In order to overcome this limitation, the sysctl output parsing was reimplemented without raw pointer deferencing. The resulting code might be slightly slower than the original one, but it is cleaner and safer. Since this fix allows go vet with GOOS=openbsd to run without any issues on all platforms, openbsd entries were also added to the "vet" Makefile target. Co-authored-by: Sergey Vinogradov <cbrpnk@gmail.com>
This commit is contained in:
parent
b49f37e9f3
commit
d6e0932b96
4
Makefile
4
Makefile
@ -58,6 +58,10 @@ vet:
|
||||
GOOS=linux GOARCH=s390x go vet ./...
|
||||
|
||||
GOOS=netbsd GOARCH=amd64 go vet ./...
|
||||
|
||||
GOOS=openbsd GOARCH=386 go vet ./...
|
||||
GOOS=openbsd GOARCH=amd64 go vet ./...
|
||||
|
||||
GOOS=solaris GOARCH=amd64 go vet ./...
|
||||
|
||||
GOOS=windows GOARCH=amd64 go vet ./...
|
||||
|
@ -3,8 +3,11 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"C"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -78,21 +81,51 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
argc := 0
|
||||
argvp := unsafe.Pointer(&buf[0])
|
||||
argv := *(**C.char)(unsafe.Pointer(argvp))
|
||||
size := unsafe.Sizeof(argv)
|
||||
/* 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
|
||||
|
||||
for argv != nil {
|
||||
strParts = append(strParts, C.GoString(argv))
|
||||
|
||||
argc++
|
||||
argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size))
|
||||
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 {
|
||||
|
@ -3,8 +3,11 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"C"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -78,21 +81,51 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
argc := 0
|
||||
argvp := unsafe.Pointer(&buf[0])
|
||||
argv := *(**C.char)(unsafe.Pointer(argvp))
|
||||
size := unsafe.Sizeof(argv)
|
||||
/* 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
|
||||
|
||||
for argv != nil {
|
||||
strParts = append(strParts, C.GoString(argv))
|
||||
|
||||
argc++
|
||||
argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size))
|
||||
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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user