diff --git a/Makefile b/Makefile index 7a540a97..39f199eb 100644 --- a/Makefile +++ b/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 ./... diff --git a/process/process_openbsd.go b/process/process_openbsd.go index 0404b4ba..902664b0 100644 --- a/process/process_openbsd.go +++ b/process/process_openbsd.go @@ -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 { diff --git a/v3/process/process_openbsd.go b/v3/process/process_openbsd.go index 7325f093..0977a11b 100644 --- a/v3/process/process_openbsd.go +++ b/v3/process/process_openbsd.go @@ -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 {