Skip to content

Commit

Permalink
Merge pull request #1530 from darkgeek/feature/netbsd-arm64-port
Browse files Browse the repository at this point in the history
Add some support for NetBSD
  • Loading branch information
shirou committed Sep 30, 2023
2 parents 2fabf15 + 66ee833 commit 826376d
Show file tree
Hide file tree
Showing 17 changed files with 631 additions and 14 deletions.
4 changes: 2 additions & 2 deletions cpu/cpu_fallback.go
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 826376d

Please sign in to comment.