1// +build freebsd 2 3package disk 4 5import ( 6 "bytes" 7 "context" 8 "encoding/binary" 9 "strconv" 10 11 "golang.org/x/sys/unix" 12 13 "github.com/shirou/gopsutil/v3/internal/common" 14) 15 16// PartitionsWithContext returns disk partition. 17// 'all' argument is ignored, see: https://github.com/giampaolo/psutil/issues/906 18func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { 19 var ret []PartitionStat 20 21 // get length 22 count, err := unix.Getfsstat(nil, unix.MNT_WAIT) 23 if err != nil { 24 return ret, err 25 } 26 27 fs := make([]unix.Statfs_t, count) 28 if _, err = unix.Getfsstat(fs, unix.MNT_WAIT); err != nil { 29 return ret, err 30 } 31 32 for _, stat := range fs { 33 opts := []string{"rw"} 34 if stat.Flags&unix.MNT_RDONLY != 0 { 35 opts = []string{"ro"} 36 } 37 if stat.Flags&unix.MNT_SYNCHRONOUS != 0 { 38 opts = append(opts, "sync") 39 } 40 if stat.Flags&unix.MNT_NOEXEC != 0 { 41 opts = append(opts, "noexec") 42 } 43 if stat.Flags&unix.MNT_NOSUID != 0 { 44 opts = append(opts, "nosuid") 45 } 46 if stat.Flags&unix.MNT_UNION != 0 { 47 opts = append(opts, "union") 48 } 49 if stat.Flags&unix.MNT_ASYNC != 0 { 50 opts = append(opts, "async") 51 } 52 if stat.Flags&unix.MNT_SUIDDIR != 0 { 53 opts = append(opts, "suiddir") 54 } 55 if stat.Flags&unix.MNT_SOFTDEP != 0 { 56 opts = append(opts, "softdep") 57 } 58 if stat.Flags&unix.MNT_NOSYMFOLLOW != 0 { 59 opts = append(opts, "nosymfollow") 60 } 61 if stat.Flags&unix.MNT_GJOURNAL != 0 { 62 opts = append(opts, "gjournal") 63 } 64 if stat.Flags&unix.MNT_MULTILABEL != 0 { 65 opts = append(opts, "multilabel") 66 } 67 if stat.Flags&unix.MNT_ACLS != 0 { 68 opts = append(opts, "acls") 69 } 70 if stat.Flags&unix.MNT_NOATIME != 0 { 71 opts = append(opts, "noatime") 72 } 73 if stat.Flags&unix.MNT_NOCLUSTERR != 0 { 74 opts = append(opts, "noclusterr") 75 } 76 if stat.Flags&unix.MNT_NOCLUSTERW != 0 { 77 opts = append(opts, "noclusterw") 78 } 79 if stat.Flags&unix.MNT_NFS4ACLS != 0 { 80 opts = append(opts, "nfsv4acls") 81 } 82 83 d := PartitionStat{ 84 Device: common.ByteToString(stat.Mntfromname[:]), 85 Mountpoint: common.ByteToString(stat.Mntonname[:]), 86 Fstype: common.ByteToString(stat.Fstypename[:]), 87 Opts: opts, 88 } 89 90 ret = append(ret, d) 91 } 92 93 return ret, nil 94} 95 96func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { 97 // statinfo->devinfo->devstat 98 // /usr/include/devinfo.h 99 ret := make(map[string]IOCountersStat) 100 101 r, err := unix.Sysctl("kern.devstat.all") 102 if err != nil { 103 return nil, err 104 } 105 buf := []byte(r) 106 length := len(buf) 107 108 count := int(uint64(length) / uint64(sizeOfdevstat)) 109 110 buf = buf[8:] // devstat.all has version in the head. 111 // parse buf to devstat 112 for i := 0; i < count; i++ { 113 b := buf[i*sizeOfdevstat : i*sizeOfdevstat+sizeOfdevstat] 114 d, err := parsedevstat(b) 115 if err != nil { 116 continue 117 } 118 un := strconv.Itoa(int(d.Unit_number)) 119 name := common.IntToString(d.Device_name[:]) + un 120 121 if len(names) > 0 && !common.StringsHas(names, name) { 122 continue 123 } 124 125 ds := IOCountersStat{ 126 ReadCount: d.Operations[devstat_READ], 127 WriteCount: d.Operations[devstat_WRITE], 128 ReadBytes: d.Bytes[devstat_READ], 129 WriteBytes: d.Bytes[devstat_WRITE], 130 ReadTime: uint64(d.Duration[devstat_READ].Compute() * 1000), 131 WriteTime: uint64(d.Duration[devstat_WRITE].Compute() * 1000), 132 IoTime: uint64(d.Busy_time.Compute() * 1000), 133 Name: name, 134 } 135 ret[name] = ds 136 } 137 138 return ret, nil 139} 140 141func (b bintime) Compute() float64 { 142 BINTIME_SCALE := 5.42101086242752217003726400434970855712890625e-20 143 return float64(b.Sec) + float64(b.Frac)*BINTIME_SCALE 144} 145 146// BT2LD(time) ((long double)(time).sec + (time).frac * BINTIME_SCALE) 147 148func parsedevstat(buf []byte) (devstat, error) { 149 var ds devstat 150 br := bytes.NewReader(buf) 151 // err := binary.Read(br, binary.LittleEndian, &ds) 152 err := common.Read(br, binary.LittleEndian, &ds) 153 if err != nil { 154 return ds, err 155 } 156 157 return ds, nil 158} 159 160func getFsType(stat unix.Statfs_t) string { 161 return common.ByteToString(stat.Fstypename[:]) 162} 163 164func SerialNumberWithContext(ctx context.Context, name string) (string, error) { 165 return "", common.ErrNotImplementedError 166} 167 168func LabelWithContext(ctx context.Context, name string) (string, error) { 169 return "", common.ErrNotImplementedError 170} 171