From d9157a9621b69ad1d8d77a1933590c416593f24f Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Sun, 1 Feb 2015 16:04:03 +0000 Subject: [PATCH] unix: add custom Sysctl args and methods SysctlUint64, SysctlRaw Add support for optional sysctl arguments which is required to support sysctls that require more than the mib identifer args as returned from nametomib such as kern.proc.pid. Add SysctlUint64 which allows sysctls that return 64 bit ints to be queried. Add SysctlRaw which allows sysctls that return structs or other unsupported types to be queried. Change-Id: If0fa23935ee09496f2df210364d8988ccd0f3db6 Reviewed-on: https://go-review.googlesource.com/14955 Reviewed-by: Ian Lance Taylor --- unix/syscall_bsd.go | 79 ++++++++++++++++++++++++++++++++---- unix/syscall_bsd_test.go | 7 ++++ unix/syscall_freebsd_test.go | 20 +++++++++ 3 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 unix/syscall_freebsd_test.go diff --git a/unix/syscall_bsd.go b/unix/syscall_bsd.go index 9679dec8..e9671764 100644 --- a/unix/syscall_bsd.go +++ b/unix/syscall_bsd.go @@ -450,16 +450,34 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err e //sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL -func Sysctl(name string) (value string, err error) { +// sysctlmib translates name to mib number and appends any additional args. +func sysctlmib(name string, args ...int) ([]_C_int, error) { // Translate name to mib number. mib, err := nametomib(name) + if err != nil { + return nil, err + } + + for _, a := range args { + mib = append(mib, _C_int(a)) + } + + return mib, nil +} + +func Sysctl(name string) (string, error) { + return SysctlArgs(name) +} + +func SysctlArgs(name string, args ...int) (string, error) { + mib, err := sysctlmib(name, args...) if err != nil { return "", err } // Find size. n := uintptr(0) - if err = sysctl(mib, nil, &n, nil, 0); err != nil { + if err := sysctl(mib, nil, &n, nil, 0); err != nil { return "", err } if n == 0 { @@ -468,7 +486,7 @@ func Sysctl(name string) (value string, err error) { // Read into buffer of that size. buf := make([]byte, n) - if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil { + if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { return "", err } @@ -479,17 +497,19 @@ func Sysctl(name string) (value string, err error) { return string(buf[0:n]), nil } -func SysctlUint32(name string) (value uint32, err error) { - // Translate name to mib number. - mib, err := nametomib(name) +func SysctlUint32(name string) (uint32, error) { + return SysctlUint32Args(name) +} + +func SysctlUint32Args(name string, args ...int) (uint32, error) { + mib, err := sysctlmib(name, args...) if err != nil { return 0, err } - // Read into buffer of that size. n := uintptr(4) buf := make([]byte, 4) - if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil { + if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { return 0, err } if n != 4 { @@ -498,6 +518,49 @@ func SysctlUint32(name string) (value uint32, err error) { return *(*uint32)(unsafe.Pointer(&buf[0])), nil } +func SysctlUint64(name string, args ...int) (uint64, error) { + mib, err := sysctlmib(name, args...) + if err != nil { + return 0, err + } + + n := uintptr(8) + buf := make([]byte, 8) + if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { + return 0, err + } + if n != 8 { + return 0, EIO + } + return *(*uint64)(unsafe.Pointer(&buf[0])), nil +} + +func SysctlRaw(name string, args ...int) ([]byte, error) { + mib, err := sysctlmib(name, args...) + if err != nil { + return nil, err + } + + // Find size. + n := uintptr(0) + if err := sysctl(mib, nil, &n, nil, 0); err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + + // Read into buffer of that size. + buf := make([]byte, n) + if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { + return nil, err + } + + // The actual call may return less than the original reported required + // size so ensure we deal with that. + return buf[:n], nil +} + //sys utimes(path string, timeval *[2]Timeval) (err error) func Utimes(path string, tv []Timeval) error { diff --git a/unix/syscall_bsd_test.go b/unix/syscall_bsd_test.go index 55d88430..0bcd741f 100644 --- a/unix/syscall_bsd_test.go +++ b/unix/syscall_bsd_test.go @@ -33,3 +33,10 @@ func TestGetfsstat(t *testing.T) { } } } + +func TestSysctlRaw(t *testing.T) { + _, err := unix.SysctlRaw("kern.proc.pid", unix.Getpid()) + if err != nil { + t.Fatal(err) + } +} diff --git a/unix/syscall_freebsd_test.go b/unix/syscall_freebsd_test.go new file mode 100644 index 00000000..6171a017 --- /dev/null +++ b/unix/syscall_freebsd_test.go @@ -0,0 +1,20 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd + +package unix_test + +import ( + "testing" + + "golang.org/x/sys/unix" +) + +func TestSysctUint64(t *testing.T) { + _, err := unix.SysctlUint64("vm.max_kernel_address") + if err != nil { + t.Fatal(err) + } +}