| // SPDX-License-Identifier: BSD-3-Clause |
| //go:build netbsd |
| |
| package disk |
| |
| import ( |
| "context" |
| "unsafe" |
| |
| "golang.org/x/sys/unix" |
| |
| "github.com/shirou/gopsutil/v4/internal/common" |
| ) |
| |
| 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(_ context.Context, _ 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 again 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 i := range buf { |
| stat := &buf[i] |
| 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(_ context.Context, _ ...string) (map[string]IOCountersStat, error) { |
| ret := make(map[string]IOCountersStat) |
| return ret, common.ErrNotImplementedError |
| } |
| |
| func UsageWithContext(_ 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(_ context.Context, _ string) (string, error) { |
| return "", common.ErrNotImplementedError |
| } |
| |
| func LabelWithContext(_ context.Context, _ string) (string, error) { |
| return "", common.ErrNotImplementedError |
| } |