148 lines
3.8 KiB
Go
148 lines
3.8 KiB
Go
//go:build solaris
|
|
// +build solaris
|
|
|
|
package disk
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/shirou/gopsutil/v3/internal/common"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
// _DEFAULT_NUM_MOUNTS is set to `cat /etc/mnttab | wc -l` rounded up to the
|
|
// nearest power of two.
|
|
_DEFAULT_NUM_MOUNTS = 32
|
|
|
|
// _MNTTAB default place to read mount information
|
|
_MNTTAB = "/etc/mnttab"
|
|
)
|
|
|
|
// A blacklist of read-only virtual filesystems. Writable filesystems are of
|
|
// operational concern and must not be included in this list.
|
|
var fsTypeBlacklist = map[string]struct{}{
|
|
"ctfs": {},
|
|
"dev": {},
|
|
"fd": {},
|
|
"lofs": {},
|
|
"lxproc": {},
|
|
"mntfs": {},
|
|
"objfs": {},
|
|
"proc": {},
|
|
}
|
|
|
|
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
|
ret := make([]PartitionStat, 0, _DEFAULT_NUM_MOUNTS)
|
|
|
|
// Scan mnttab(4)
|
|
f, err := os.Open(_MNTTAB)
|
|
if err != nil {
|
|
}
|
|
defer func() {
|
|
if err == nil {
|
|
err = f.Close()
|
|
} else {
|
|
f.Close()
|
|
}
|
|
}()
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
fields := strings.Split(scanner.Text(), "\t")
|
|
|
|
if _, found := fsTypeBlacklist[fields[2]]; found {
|
|
continue
|
|
}
|
|
|
|
ret = append(ret, PartitionStat{
|
|
// NOTE(seanc@): Device isn't exactly accurate: from mnttab(4): "The name
|
|
// of the resource that has been mounted." Ideally this value would come
|
|
// from Statvfs_t.Fsid but I'm leaving it to the caller to traverse
|
|
// unix.Statvfs().
|
|
Device: fields[0],
|
|
Mountpoint: fields[1],
|
|
Fstype: fields[2],
|
|
Opts: strings.Split(fields[3], ","),
|
|
})
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, fmt.Errorf("unable to scan %q: %v", _MNTTAB, err)
|
|
}
|
|
|
|
return ret, err
|
|
}
|
|
|
|
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
|
return nil, common.ErrNotImplementedError
|
|
}
|
|
|
|
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
|
statvfs := unix.Statvfs_t{}
|
|
if err := unix.Statvfs(path, &statvfs); err != nil {
|
|
return nil, fmt.Errorf("unable to call statvfs(2) on %q: %v", path, err)
|
|
}
|
|
|
|
usageStat := &UsageStat{
|
|
Path: path,
|
|
Fstype: common.IntToString(statvfs.Basetype[:]),
|
|
Total: statvfs.Blocks * statvfs.Frsize,
|
|
Free: statvfs.Bfree * statvfs.Frsize,
|
|
Used: (statvfs.Blocks - statvfs.Bfree) * statvfs.Frsize,
|
|
|
|
// NOTE: ZFS (and FreeBZSD's UFS2) use dynamic inode/dnode allocation.
|
|
// Explicitly return a near-zero value for InodesUsedPercent so that nothing
|
|
// attempts to garbage collect based on a lack of available inodes/dnodes.
|
|
// Similarly, don't use the zero value to prevent divide-by-zero situations
|
|
// and inject a faux near-zero value. Filesystems evolve. Has your
|
|
// filesystem evolved? Probably not if you care about the number of
|
|
// available inodes.
|
|
InodesTotal: 1024.0 * 1024.0,
|
|
InodesUsed: 1024.0,
|
|
InodesFree: math.MaxUint64,
|
|
InodesUsedPercent: (1024.0 / (1024.0 * 1024.0)) * 100.0,
|
|
}
|
|
|
|
usageStat.UsedPercent = (float64(usageStat.Used) / float64(usageStat.Total)) * 100.0
|
|
|
|
return usageStat, nil
|
|
}
|
|
|
|
func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
|
|
out, err := invoke.CommandWithContext(ctx, "cfgadm", "-ls", "select=type(disk),cols=ap_id:info,cols2=,noheadings")
|
|
if err != nil {
|
|
return "", fmt.Errorf("exec cfgadm: %w", err)
|
|
}
|
|
|
|
suf := "::" + strings.TrimPrefix(name, "/dev/")
|
|
s := bufio.NewScanner(bytes.NewReader(out))
|
|
for s.Scan() {
|
|
flds := strings.Fields(s.Text())
|
|
if strings.HasSuffix(flds[0], suf) {
|
|
flen := len(flds)
|
|
if flen >= 3 {
|
|
for i, f := range flds {
|
|
if i > 0 && i < flen-1 && f == "SN:" {
|
|
return flds[i+1], nil
|
|
}
|
|
}
|
|
}
|
|
return "", nil
|
|
}
|
|
}
|
|
if err := s.Err(); err != nil {
|
|
return "", err
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
func LabelWithContext(ctx context.Context, name string) (string, error) {
|
|
return "", common.ErrNotImplementedError
|
|
}
|