Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some support for NetBSD #1530

Merged
merged 19 commits into from Sep 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions cpu/cpu_fallback.go
@@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !dragonfly && !plan9 && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!dragonfly,!plan9,!aix
//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!solaris,!windows,!dragonfly,!plan9,!aix

package cpu

Expand Down
119 changes: 119 additions & 0 deletions cpu/cpu_netbsd.go
@@ -0,0 +1,119 @@
//go:build netbsd
// +build netbsd

package cpu

import (
"context"
"fmt"
"runtime"
"unsafe"

"github.com/shirou/gopsutil/v3/internal/common"
"github.com/tklauser/go-sysconf"
"golang.org/x/sys/unix"
)

const (
// sys/sysctl.h
ctlKern = 1 // "high kernel": proc, limits
ctlHw = 6 // CTL_HW
kernCpTime = 51 // KERN_CPTIME
)

var ClocksPerSec = float64(100)

func init() {
clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
// ignore errors
if err == nil {
ClocksPerSec = float64(clkTck)
}
}

func Times(percpu bool) ([]TimesStat, error) {
return TimesWithContext(context.Background(), percpu)
}

func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) {
if !percpu {
mib := []int32{ctlKern, kernCpTime}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}
times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
stat := TimesStat{
CPU: "cpu-total",
User: float64(times.User),
Nice: float64(times.Nice),
System: float64(times.Sys),
Idle: float64(times.Idle),
Irq: float64(times.Intr),
}
return []TimesStat{stat}, nil
}

ncpu, err := unix.SysctlUint32("hw.ncpu")
if err != nil {
return
}

var i uint32
for i = 0; i < ncpu; i++ {
mib := []int32{ctlKern, kernCpTime, int32(i)}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}

stats := (*cpuTimes)(unsafe.Pointer(&buf[0]))
ret = append(ret, TimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(stats.User),
Nice: float64(stats.Nice),
System: float64(stats.Sys),
Idle: float64(stats.Idle),
Irq: float64(stats.Intr),
})
}

return ret, nil
}

// Returns only one (minimal) CPUInfoStat on NetBSD
func Info() ([]InfoStat, error) {
return InfoWithContext(context.Background())
}

func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
var ret []InfoStat
var err error

c := InfoStat{}

mhz, err := unix.Sysctl("machdep.dmi.processor-frequency")
if err != nil {
return nil, err
}
_, err = fmt.Sscanf(mhz, "%f", &c.Mhz)
if err != nil {
return nil, err
}

ncpu, err := unix.SysctlUint32("hw.ncpuonline")
if err != nil {
return nil, err
}
c.Cores = int32(ncpu)

if c.ModelName, err = unix.Sysctl("machdep.dmi.processor-version"); err != nil {
return nil, err
}

return append(ret, c), nil
}

func CountsWithContext(ctx context.Context, logical bool) (int, error) {
return runtime.NumCPU(), nil
}
9 changes: 9 additions & 0 deletions cpu/cpu_netbsd_amd64.go
@@ -0,0 +1,9 @@
package cpu

type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}
9 changes: 9 additions & 0 deletions cpu/cpu_netbsd_arm64.go
@@ -0,0 +1,9 @@
package cpu

type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}
4 changes: 2 additions & 2 deletions disk/disk_fallback.go
@@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris,!aix
//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !windows && !solaris && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!windows,!solaris,!aix

package disk

Expand Down
152 changes: 152 additions & 0 deletions disk/disk_netbsd.go
@@ -0,0 +1,152 @@
//go:build netbsd
// +build netbsd

package disk

import (
"context"
"unsafe"

"github.com/shirou/gopsutil/v3/internal/common"
"golang.org/x/sys/unix"
)

const (
// see sys/fstypes.h and `man 5 statvfs`
MNT_RDONLY = 0x00000001 /* read only filesystem */
MNT_SYNCHRONOUS = 0x00000002 /* file system written synchronously */
MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */
MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */
MNT_NODEV = 0x00000010 /* don't interpret special files */
MNT_ASYNC = 0x00000040 /* file system written asynchronously */
MNT_NOATIME = 0x04000000 /* Never update access times in fs */
MNT_SOFTDEP = 0x80000000 /* Use soft dependencies */
)

func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
var ret []PartitionStat

flag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h

// get required buffer size
emptyBufSize := 0
r, _, err := unix.Syscall(
483, // SYS___getvfsstat90 syscall
uintptr(unsafe.Pointer(nil)),
uintptr(unsafe.Pointer(&emptyBufSize)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return ret, err
}
mountedFsCount := uint64(r)

// calculate the buffer size
bufSize := sizeOfStatvfs * mountedFsCount
buf := make([]Statvfs, mountedFsCount)

// request agian to get desired mount data
_, _, err = unix.Syscall(
483, // SYS___getvfsstat90 syscall
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&bufSize)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return ret, err
}

for _, stat := range buf {
opts := []string{"rw"}
if stat.Flag&MNT_RDONLY != 0 {
opts = []string{"rw"}
}
if stat.Flag&MNT_SYNCHRONOUS != 0 {
opts = append(opts, "sync")
}
if stat.Flag&MNT_NOEXEC != 0 {
opts = append(opts, "noexec")
}
if stat.Flag&MNT_NOSUID != 0 {
opts = append(opts, "nosuid")
}
if stat.Flag&MNT_NODEV != 0 {
opts = append(opts, "nodev")
}
if stat.Flag&MNT_ASYNC != 0 {
opts = append(opts, "async")
}
if stat.Flag&MNT_SOFTDEP != 0 {
opts = append(opts, "softdep")
}
if stat.Flag&MNT_NOATIME != 0 {
opts = append(opts, "noatime")
}

d := PartitionStat{
Device: common.ByteToString([]byte(stat.Mntfromname[:])),
Mountpoint: common.ByteToString([]byte(stat.Mntonname[:])),
Fstype: common.ByteToString([]byte(stat.Fstypename[:])),
Opts: opts,
}

ret = append(ret, d)
}

return ret, nil
}

func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat)
return ret, common.ErrNotImplementedError
}

func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
stat := Statvfs{}
flag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h

_path, e := unix.BytePtrFromString(path)
if e != nil {
return nil, e
}

_, _, err := unix.Syscall(
484, // SYS___statvfs190, see sys/syscall.h
uintptr(unsafe.Pointer(_path)),
uintptr(unsafe.Pointer(&stat)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return nil, err
}

// frsize is the real block size on NetBSD. See discuss here: https://bugzilla.samba.org/show_bug.cgi?id=11810
bsize := stat.Frsize
ret := &UsageStat{
Path: path,
Fstype: getFsType(stat),
Total: (uint64(stat.Blocks) * uint64(bsize)),
Free: (uint64(stat.Bavail) * uint64(bsize)),
InodesTotal: (uint64(stat.Files)),
InodesFree: (uint64(stat.Ffree)),
}

ret.InodesUsed = (ret.InodesTotal - ret.InodesFree)
ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0
ret.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize)
ret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0

return ret, nil
}

func getFsType(stat Statvfs) string {
return common.ByteToString(stat.Fstypename[:])
}

func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
return "", common.ErrNotImplementedError
}

func LabelWithContext(ctx context.Context, name string) (string, error) {
return "", common.ErrNotImplementedError
}
45 changes: 45 additions & 0 deletions disk/disk_netbsd_amd64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.