diff --git a/internal/sysinfo/memtotal_openbsd_amd64.go b/internal/sysinfo/memtotal_openbsd_amd64.go new file mode 100644 index 000000000..2dc20960d --- /dev/null +++ b/internal/sysinfo/memtotal_openbsd_amd64.go @@ -0,0 +1,35 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "syscall" + "unsafe" +) + +// PhysicalMemoryBytes returns the total amount of host memory. +func PhysicalMemoryBytes() (uint64, error) { + mib := []int32{6 /* CTL_HW */, 19 /* HW_PHYSMEM64 */} + + buf := make([]byte, 8) + bufLen := uintptr(8) + + _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), + uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)), + uintptr(0), uintptr(0)) + + if e1 != 0 { + return 0, e1 + } + + switch bufLen { + case 4: + return uint64(*(*uint32)(unsafe.Pointer(&buf[0]))), nil + case 8: + return *(*uint64)(unsafe.Pointer(&buf[0])), nil + default: + return 0, syscall.EIO + } +} diff --git a/internal/sysinfo/memtotal_openbsd_test.go b/internal/sysinfo/memtotal_openbsd_test.go new file mode 100644 index 000000000..e12140848 --- /dev/null +++ b/internal/sysinfo/memtotal_openbsd_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "errors" + "os/exec" + "regexp" + "strconv" + "testing" +) + +var re = regexp.MustCompile(`hw\.physmem=(\d+)`) + +func openbsdSysctlMemoryBytes() (uint64, error) { + out, err := exec.Command("/sbin/sysctl", "hw.physmem").Output() + if err != nil { + return 0, err + } + + match := re.FindSubmatch(out) + if match == nil { + return 0, errors.New("memory size not found in sysctl output") + } + + bts, err := strconv.ParseUint(string(match[1]), 10, 64) + if err != nil { + return 0, err + } + + return bts, nil +} + +func TestPhysicalMemoryBytes(t *testing.T) { + mem, err := PhysicalMemoryBytes() + if err != nil { + t.Fatal(err) + } + + mem2, err := openbsdSysctlMemoryBytes() + if nil != err { + t.Fatal(err) + } + + if mem != mem2 { + t.Errorf("Expected %d, got %d\n", mem2, mem) + } +} diff --git a/v3/internal/sysinfo/memtotal_openbsd_amd64.go b/v3/internal/sysinfo/memtotal_openbsd_amd64.go new file mode 100644 index 000000000..2dc20960d --- /dev/null +++ b/v3/internal/sysinfo/memtotal_openbsd_amd64.go @@ -0,0 +1,35 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "syscall" + "unsafe" +) + +// PhysicalMemoryBytes returns the total amount of host memory. +func PhysicalMemoryBytes() (uint64, error) { + mib := []int32{6 /* CTL_HW */, 19 /* HW_PHYSMEM64 */} + + buf := make([]byte, 8) + bufLen := uintptr(8) + + _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), + uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)), + uintptr(0), uintptr(0)) + + if e1 != 0 { + return 0, e1 + } + + switch bufLen { + case 4: + return uint64(*(*uint32)(unsafe.Pointer(&buf[0]))), nil + case 8: + return *(*uint64)(unsafe.Pointer(&buf[0])), nil + default: + return 0, syscall.EIO + } +} diff --git a/v3/internal/sysinfo/memtotal_openbsd_test.go b/v3/internal/sysinfo/memtotal_openbsd_test.go new file mode 100644 index 000000000..e12140848 --- /dev/null +++ b/v3/internal/sysinfo/memtotal_openbsd_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sysinfo + +import ( + "errors" + "os/exec" + "regexp" + "strconv" + "testing" +) + +var re = regexp.MustCompile(`hw\.physmem=(\d+)`) + +func openbsdSysctlMemoryBytes() (uint64, error) { + out, err := exec.Command("/sbin/sysctl", "hw.physmem").Output() + if err != nil { + return 0, err + } + + match := re.FindSubmatch(out) + if match == nil { + return 0, errors.New("memory size not found in sysctl output") + } + + bts, err := strconv.ParseUint(string(match[1]), 10, 64) + if err != nil { + return 0, err + } + + return bts, nil +} + +func TestPhysicalMemoryBytes(t *testing.T) { + mem, err := PhysicalMemoryBytes() + if err != nil { + t.Fatal(err) + } + + mem2, err := openbsdSysctlMemoryBytes() + if nil != err { + t.Fatal(err) + } + + if mem != mem2 { + t.Errorf("Expected %d, got %d\n", mem2, mem) + } +}