disk_solaris.go 3.8 KB

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