//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 }