1// +build solaris
2
3package disk
4
5import (
6	"bufio"
7	"context"
8	"fmt"
9	"math"
10	"os"
11	"strings"
12
13	"github.com/shirou/gopsutil/v3/internal/common"
14	"golang.org/x/sys/unix"
15)
16
17const (
18	// _DEFAULT_NUM_MOUNTS is set to `cat /etc/mnttab | wc -l` rounded up to the
19	// nearest power of two.
20	_DEFAULT_NUM_MOUNTS = 32
21
22	// _MNTTAB default place to read mount information
23	_MNTTAB = "/etc/mnttab"
24)
25
26var (
27	// A blacklist of read-only virtual filesystems.  Writable filesystems are of
28	// operational concern and must not be included in this list.
29	fsTypeBlacklist = map[string]struct{}{
30		"ctfs":   struct{}{},
31		"dev":    struct{}{},
32		"fd":     struct{}{},
33		"lofs":   struct{}{},
34		"lxproc": struct{}{},
35		"mntfs":  struct{}{},
36		"objfs":  struct{}{},
37		"proc":   struct{}{},
38	}
39)
40
41func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
42	ret := make([]PartitionStat, 0, _DEFAULT_NUM_MOUNTS)
43
44	// Scan mnttab(4)
45	f, err := os.Open(_MNTTAB)
46	if err != nil {
47	}
48	defer func() {
49		if err == nil {
50			err = f.Close()
51		} else {
52			f.Close()
53		}
54	}()
55
56	scanner := bufio.NewScanner(f)
57	for scanner.Scan() {
58		fields := strings.Split(scanner.Text(), "\t")
59
60		if _, found := fsTypeBlacklist[fields[2]]; found {
61			continue
62		}
63
64		ret = append(ret, PartitionStat{
65			// NOTE(seanc@): Device isn't exactly accurate: from mnttab(4): "The name
66			// of the resource that has been mounted."  Ideally this value would come
67			// from Statvfs_t.Fsid but I'm leaving it to the caller to traverse
68			// unix.Statvfs().
69			Device:     fields[0],
70			Mountpoint: fields[1],
71			Fstype:     fields[2],
72			Opts:       strings.Split(fields[3], ","),
73		})
74	}
75	if err := scanner.Err(); err != nil {
76		return nil, fmt.Errorf("unable to scan %q: %v", _MNTTAB, err)
77	}
78
79	return ret, err
80}
81
82func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
83	return nil, common.ErrNotImplementedError
84}
85
86func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
87	statvfs := unix.Statvfs_t{}
88	if err := unix.Statvfs(path, &statvfs); err != nil {
89		return nil, fmt.Errorf("unable to call statvfs(2) on %q: %v", path, err)
90	}
91
92	usageStat := &UsageStat{
93		Path:   path,
94		Fstype: common.IntToString(statvfs.Basetype[:]),
95		Total:  statvfs.Blocks * statvfs.Frsize,
96		Free:   statvfs.Bfree * statvfs.Frsize,
97		Used:   (statvfs.Blocks - statvfs.Bfree) * statvfs.Frsize,
98
99		// NOTE: ZFS (and FreeBZSD's UFS2) use dynamic inode/dnode allocation.
100		// Explicitly return a near-zero value for InodesUsedPercent so that nothing
101		// attempts to garbage collect based on a lack of available inodes/dnodes.
102		// Similarly, don't use the zero value to prevent divide-by-zero situations
103		// and inject a faux near-zero value.  Filesystems evolve.  Has your
104		// filesystem evolved?  Probably not if you care about the number of
105		// available inodes.
106		InodesTotal:       1024.0 * 1024.0,
107		InodesUsed:        1024.0,
108		InodesFree:        math.MaxUint64,
109		InodesUsedPercent: (1024.0 / (1024.0 * 1024.0)) * 100.0,
110	}
111
112	usageStat.UsedPercent = (float64(usageStat.Used) / float64(usageStat.Total)) * 100.0
113
114	return usageStat, nil
115}
116func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
117	return "", common.ErrNotImplementedError
118}
119
120func LabelWithContext(ctx context.Context, name string) (string, error) {
121	return "", common.ErrNotImplementedError
122}
123