1
2
3 package disk
4
5 import (
6 "bufio"
7 "bytes"
8 "context"
9 "fmt"
10 "io/ioutil"
11 "os"
12 "path/filepath"
13 "strconv"
14 "strings"
15
16 "github.com/shirou/gopsutil/internal/common"
17 "golang.org/x/sys/unix"
18 )
19
20 const (
21 SectorSize = 512
22 )
23 const (
24
25 ADFS_SUPER_MAGIC = 0xadf5
26 AFFS_SUPER_MAGIC = 0xADFF
27 BDEVFS_MAGIC = 0x62646576
28 BEFS_SUPER_MAGIC = 0x42465331
29 BFS_MAGIC = 0x1BADFACE
30 BINFMTFS_MAGIC = 0x42494e4d
31 BTRFS_SUPER_MAGIC = 0x9123683E
32 CGROUP_SUPER_MAGIC = 0x27e0eb
33 CIFS_MAGIC_NUMBER = 0xFF534D42
34 CODA_SUPER_MAGIC = 0x73757245
35 COH_SUPER_MAGIC = 0x012FF7B7
36 CRAMFS_MAGIC = 0x28cd3d45
37 DEBUGFS_MAGIC = 0x64626720
38 DEVFS_SUPER_MAGIC = 0x1373
39 DEVPTS_SUPER_MAGIC = 0x1cd1
40 EFIVARFS_MAGIC = 0xde5e81e4
41 EFS_SUPER_MAGIC = 0x00414A53
42 EXT_SUPER_MAGIC = 0x137D
43 EXT2_OLD_SUPER_MAGIC = 0xEF51
44 EXT2_SUPER_MAGIC = 0xEF53
45 EXT3_SUPER_MAGIC = 0xEF53
46 EXT4_SUPER_MAGIC = 0xEF53
47 FUSE_SUPER_MAGIC = 0x65735546
48 FUTEXFS_SUPER_MAGIC = 0xBAD1DEA
49 HFS_SUPER_MAGIC = 0x4244
50 HFSPLUS_SUPER_MAGIC = 0x482b
51 HOSTFS_SUPER_MAGIC = 0x00c0ffee
52 HPFS_SUPER_MAGIC = 0xF995E849
53 HUGETLBFS_MAGIC = 0x958458f6
54 ISOFS_SUPER_MAGIC = 0x9660
55 JFFS2_SUPER_MAGIC = 0x72b6
56 JFS_SUPER_MAGIC = 0x3153464a
57 MINIX_SUPER_MAGIC = 0x137F
58 MINIX_SUPER_MAGIC2 = 0x138F
59 MINIX2_SUPER_MAGIC = 0x2468
60 MINIX2_SUPER_MAGIC2 = 0x2478
61 MINIX3_SUPER_MAGIC = 0x4d5a
62 MQUEUE_MAGIC = 0x19800202
63 MSDOS_SUPER_MAGIC = 0x4d44
64 NCP_SUPER_MAGIC = 0x564c
65 NFS_SUPER_MAGIC = 0x6969
66 NILFS_SUPER_MAGIC = 0x3434
67 NTFS_SB_MAGIC = 0x5346544e
68 OCFS2_SUPER_MAGIC = 0x7461636f
69 OPENPROM_SUPER_MAGIC = 0x9fa1
70 PIPEFS_MAGIC = 0x50495045
71 PROC_SUPER_MAGIC = 0x9fa0
72 PSTOREFS_MAGIC = 0x6165676C
73 QNX4_SUPER_MAGIC = 0x002f
74 QNX6_SUPER_MAGIC = 0x68191122
75 RAMFS_MAGIC = 0x858458f6
76 REISERFS_SUPER_MAGIC = 0x52654973
77 ROMFS_MAGIC = 0x7275
78 SELINUX_MAGIC = 0xf97cff8c
79 SMACK_MAGIC = 0x43415d53
80 SMB_SUPER_MAGIC = 0x517B
81 SOCKFS_MAGIC = 0x534F434B
82 SQUASHFS_MAGIC = 0x73717368
83 SYSFS_MAGIC = 0x62656572
84 SYSV2_SUPER_MAGIC = 0x012FF7B6
85 SYSV4_SUPER_MAGIC = 0x012FF7B5
86 TMPFS_MAGIC = 0x01021994
87 UDF_SUPER_MAGIC = 0x15013346
88 UFS_MAGIC = 0x00011954
89 USBDEVICE_SUPER_MAGIC = 0x9fa2
90 V9FS_MAGIC = 0x01021997
91 VXFS_SUPER_MAGIC = 0xa501FCF5
92 XENFS_SUPER_MAGIC = 0xabba1974
93 XENIX_SUPER_MAGIC = 0x012FF7B4
94 XFS_SUPER_MAGIC = 0x58465342
95 _XIAFS_SUPER_MAGIC = 0x012FD16D
96
97 AFS_SUPER_MAGIC = 0x5346414F
98 AUFS_SUPER_MAGIC = 0x61756673
99 ANON_INODE_FS_SUPER_MAGIC = 0x09041934
100 CEPH_SUPER_MAGIC = 0x00C36400
101 ECRYPTFS_SUPER_MAGIC = 0xF15F
102 FAT_SUPER_MAGIC = 0x4006
103 FHGFS_SUPER_MAGIC = 0x19830326
104 FUSEBLK_SUPER_MAGIC = 0x65735546
105 FUSECTL_SUPER_MAGIC = 0x65735543
106 GFS_SUPER_MAGIC = 0x1161970
107 GPFS_SUPER_MAGIC = 0x47504653
108 MTD_INODE_FS_SUPER_MAGIC = 0x11307854
109 INOTIFYFS_SUPER_MAGIC = 0x2BAD1DEA
110 ISOFS_R_WIN_SUPER_MAGIC = 0x4004
111 ISOFS_WIN_SUPER_MAGIC = 0x4000
112 JFFS_SUPER_MAGIC = 0x07C0
113 KAFS_SUPER_MAGIC = 0x6B414653
114 LUSTRE_SUPER_MAGIC = 0x0BD00BD0
115 NFSD_SUPER_MAGIC = 0x6E667364
116 PANFS_SUPER_MAGIC = 0xAAD7AAEA
117 RPC_PIPEFS_SUPER_MAGIC = 0x67596969
118 SECURITYFS_SUPER_MAGIC = 0x73636673
119 UFS_BYTESWAPPED_SUPER_MAGIC = 0x54190100
120 VMHGFS_SUPER_MAGIC = 0xBACBACBC
121 VZFS_SUPER_MAGIC = 0x565A4653
122 ZFS_SUPER_MAGIC = 0x2FC12FC1
123 )
124
125
126 var fsTypeMap = map[int64]string{
127 ADFS_SUPER_MAGIC: "adfs",
128 AFFS_SUPER_MAGIC: "affs",
129 AFS_SUPER_MAGIC: "afs",
130 ANON_INODE_FS_SUPER_MAGIC: "anon-inode FS",
131 AUFS_SUPER_MAGIC: "aufs",
132
133 BEFS_SUPER_MAGIC: "befs",
134 BDEVFS_MAGIC: "bdevfs",
135 BFS_MAGIC: "bfs",
136 BINFMTFS_MAGIC: "binfmt_misc",
137 BTRFS_SUPER_MAGIC: "btrfs",
138 CEPH_SUPER_MAGIC: "ceph",
139 CGROUP_SUPER_MAGIC: "cgroupfs",
140 CIFS_MAGIC_NUMBER: "cifs",
141 CODA_SUPER_MAGIC: "coda",
142 COH_SUPER_MAGIC: "coh",
143 CRAMFS_MAGIC: "cramfs",
144 DEBUGFS_MAGIC: "debugfs",
145 DEVFS_SUPER_MAGIC: "devfs",
146 DEVPTS_SUPER_MAGIC: "devpts",
147 ECRYPTFS_SUPER_MAGIC: "ecryptfs",
148 EFS_SUPER_MAGIC: "efs",
149 EXT_SUPER_MAGIC: "ext",
150 EXT2_SUPER_MAGIC: "ext2/ext3",
151 EXT2_OLD_SUPER_MAGIC: "ext2",
152 FAT_SUPER_MAGIC: "fat",
153 FHGFS_SUPER_MAGIC: "fhgfs",
154 FUSEBLK_SUPER_MAGIC: "fuseblk",
155 FUSECTL_SUPER_MAGIC: "fusectl",
156 FUTEXFS_SUPER_MAGIC: "futexfs",
157 GFS_SUPER_MAGIC: "gfs/gfs2",
158 GPFS_SUPER_MAGIC: "gpfs",
159 HFS_SUPER_MAGIC: "hfs",
160 HFSPLUS_SUPER_MAGIC: "hfsplus",
161 HPFS_SUPER_MAGIC: "hpfs",
162 HUGETLBFS_MAGIC: "hugetlbfs",
163 MTD_INODE_FS_SUPER_MAGIC: "inodefs",
164 INOTIFYFS_SUPER_MAGIC: "inotifyfs",
165 ISOFS_SUPER_MAGIC: "isofs",
166 ISOFS_R_WIN_SUPER_MAGIC: "isofs",
167 ISOFS_WIN_SUPER_MAGIC: "isofs",
168 JFFS_SUPER_MAGIC: "jffs",
169 JFFS2_SUPER_MAGIC: "jffs2",
170 JFS_SUPER_MAGIC: "jfs",
171 KAFS_SUPER_MAGIC: "k-afs",
172 LUSTRE_SUPER_MAGIC: "lustre",
173 MINIX_SUPER_MAGIC: "minix",
174 MINIX_SUPER_MAGIC2: "minix (30 char.)",
175 MINIX2_SUPER_MAGIC: "minix v2",
176 MINIX2_SUPER_MAGIC2: "minix v2 (30 char.)",
177 MINIX3_SUPER_MAGIC: "minix3",
178 MQUEUE_MAGIC: "mqueue",
179 MSDOS_SUPER_MAGIC: "msdos",
180 NCP_SUPER_MAGIC: "novell",
181 NFS_SUPER_MAGIC: "nfs",
182 NFSD_SUPER_MAGIC: "nfsd",
183 NILFS_SUPER_MAGIC: "nilfs",
184 NTFS_SB_MAGIC: "ntfs",
185 OPENPROM_SUPER_MAGIC: "openprom",
186 OCFS2_SUPER_MAGIC: "ocfs2",
187 PANFS_SUPER_MAGIC: "panfs",
188 PIPEFS_MAGIC: "pipefs",
189 PROC_SUPER_MAGIC: "proc",
190 PSTOREFS_MAGIC: "pstorefs",
191 QNX4_SUPER_MAGIC: "qnx4",
192 QNX6_SUPER_MAGIC: "qnx6",
193 RAMFS_MAGIC: "ramfs",
194 REISERFS_SUPER_MAGIC: "reiserfs",
195 ROMFS_MAGIC: "romfs",
196 RPC_PIPEFS_SUPER_MAGIC: "rpc_pipefs",
197 SECURITYFS_SUPER_MAGIC: "securityfs",
198 SELINUX_MAGIC: "selinux",
199 SMB_SUPER_MAGIC: "smb",
200 SOCKFS_MAGIC: "sockfs",
201 SQUASHFS_MAGIC: "squashfs",
202 SYSFS_MAGIC: "sysfs",
203 SYSV2_SUPER_MAGIC: "sysv2",
204 SYSV4_SUPER_MAGIC: "sysv4",
205 TMPFS_MAGIC: "tmpfs",
206 UDF_SUPER_MAGIC: "udf",
207 UFS_MAGIC: "ufs",
208 UFS_BYTESWAPPED_SUPER_MAGIC: "ufs",
209 USBDEVICE_SUPER_MAGIC: "usbdevfs",
210 V9FS_MAGIC: "v9fs",
211 VMHGFS_SUPER_MAGIC: "vmhgfs",
212 VXFS_SUPER_MAGIC: "vxfs",
213 VZFS_SUPER_MAGIC: "vzfs",
214 XENFS_SUPER_MAGIC: "xenfs",
215 XENIX_SUPER_MAGIC: "xenix",
216 XFS_SUPER_MAGIC: "xfs",
217 _XIAFS_SUPER_MAGIC: "xia",
218 ZFS_SUPER_MAGIC: "zfs",
219 }
220
221 func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
222 useMounts := false
223
224 filename := common.HostProc("1/mountinfo")
225 lines, err := common.ReadLines(filename)
226 if err != nil {
227 if err != err.(*os.PathError) {
228 return nil, err
229 }
230
231 useMounts = true
232 filename = common.HostProc("1/mounts")
233 lines, err = common.ReadLines(filename)
234 if err != nil {
235 return nil, err
236 }
237 }
238
239 fs, err := getFileSystems()
240 if err != nil && !all {
241 return nil, err
242 }
243
244 ret := make([]PartitionStat, 0, len(lines))
245
246 for _, line := range lines {
247 var d PartitionStat
248 if useMounts {
249 fields := strings.Fields(line)
250
251 d = PartitionStat{
252 Device: fields[0],
253 Mountpoint: unescapeFstab(fields[1]),
254 Fstype: fields[2],
255 Opts: fields[3],
256 }
257
258 if !all {
259 if d.Device == "none" || !common.StringsHas(fs, d.Fstype) {
260 continue
261 }
262 }
263 } else {
264
265
266
267
268
269 parts := strings.Split(line, " - ")
270 if len(parts) != 2 {
271 return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", filename, line)
272 }
273
274 fields := strings.Fields(parts[0])
275 blockDeviceID := fields[2]
276 mountPoint := fields[4]
277 mountOpts := fields[5]
278
279 if rootDir := fields[3]; rootDir != "" && rootDir != "/" {
280 if len(mountOpts) == 0 {
281 mountOpts = "bind"
282 } else {
283 mountOpts = "bind," + mountOpts
284 }
285 }
286
287 fields = strings.Fields(parts[1])
288 fstype := fields[0]
289 device := fields[1]
290
291 d = PartitionStat{
292 Device: device,
293 Mountpoint: unescapeFstab(mountPoint),
294 Fstype: fstype,
295 Opts: mountOpts,
296 }
297
298 if !all {
299 if d.Device == "none" || !common.StringsHas(fs, d.Fstype) {
300 continue
301 }
302 }
303
304 if strings.HasPrefix(d.Device, "/dev/mapper/") {
305 devpath, err := filepath.EvalSymlinks(common.HostDev(strings.Replace(d.Device, "/dev", "", -1)))
306 if err == nil {
307 d.Device = devpath
308 }
309 }
310
311
312
313 if d.Device == "/dev/root" {
314 devpath, err := os.Readlink(common.HostSys("/dev/block/" + blockDeviceID))
315 if err != nil {
316 return nil, err
317 }
318 d.Device = strings.Replace(d.Device, "root", filepath.Base(devpath), 1)
319 }
320 }
321 ret = append(ret, d)
322 }
323
324 return ret, nil
325 }
326
327
328 func getFileSystems() ([]string, error) {
329 filename := common.HostProc("filesystems")
330 lines, err := common.ReadLines(filename)
331 if err != nil {
332 return nil, err
333 }
334 var ret []string
335 for _, line := range lines {
336 if !strings.HasPrefix(line, "nodev") {
337 ret = append(ret, strings.TrimSpace(line))
338 continue
339 }
340 t := strings.Split(line, "\t")
341 if len(t) != 2 || t[1] != "zfs" {
342 continue
343 }
344 ret = append(ret, strings.TrimSpace(t[1]))
345 }
346
347 return ret, nil
348 }
349
350 func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
351 filename := common.HostProc("diskstats")
352 lines, err := common.ReadLines(filename)
353 if err != nil {
354 return nil, err
355 }
356 ret := make(map[string]IOCountersStat, 0)
357 empty := IOCountersStat{}
358
359
360 for i, name := range names {
361 names[i] = filepath.Base(name)
362 }
363
364 for _, line := range lines {
365 fields := strings.Fields(line)
366 if len(fields) < 14 {
367
368 continue
369 }
370 name := fields[2]
371
372 if len(names) > 0 && !common.StringsHas(names, name) {
373 continue
374 }
375
376 reads, err := strconv.ParseUint((fields[3]), 10, 64)
377 if err != nil {
378 return ret, err
379 }
380 mergedReads, err := strconv.ParseUint((fields[4]), 10, 64)
381 if err != nil {
382 return ret, err
383 }
384 rbytes, err := strconv.ParseUint((fields[5]), 10, 64)
385 if err != nil {
386 return ret, err
387 }
388 rtime, err := strconv.ParseUint((fields[6]), 10, 64)
389 if err != nil {
390 return ret, err
391 }
392 writes, err := strconv.ParseUint((fields[7]), 10, 64)
393 if err != nil {
394 return ret, err
395 }
396 mergedWrites, err := strconv.ParseUint((fields[8]), 10, 64)
397 if err != nil {
398 return ret, err
399 }
400 wbytes, err := strconv.ParseUint((fields[9]), 10, 64)
401 if err != nil {
402 return ret, err
403 }
404 wtime, err := strconv.ParseUint((fields[10]), 10, 64)
405 if err != nil {
406 return ret, err
407 }
408 iopsInProgress, err := strconv.ParseUint((fields[11]), 10, 64)
409 if err != nil {
410 return ret, err
411 }
412 iotime, err := strconv.ParseUint((fields[12]), 10, 64)
413 if err != nil {
414 return ret, err
415 }
416 weightedIO, err := strconv.ParseUint((fields[13]), 10, 64)
417 if err != nil {
418 return ret, err
419 }
420 d := IOCountersStat{
421 ReadBytes: rbytes * SectorSize,
422 WriteBytes: wbytes * SectorSize,
423 ReadCount: reads,
424 WriteCount: writes,
425 MergedReadCount: mergedReads,
426 MergedWriteCount: mergedWrites,
427 ReadTime: rtime,
428 WriteTime: wtime,
429 IopsInProgress: iopsInProgress,
430 IoTime: iotime,
431 WeightedIO: weightedIO,
432 }
433 if d == empty {
434 continue
435 }
436 d.Name = name
437
438 d.SerialNumber = GetDiskSerialNumber(name)
439 d.Label = GetLabel(name)
440
441 ret[name] = d
442 }
443 return ret, nil
444 }
445
446
447
448 func GetDiskSerialNumber(name string) string {
449 return GetDiskSerialNumberWithContext(context.Background(), name)
450 }
451
452 func GetDiskSerialNumberWithContext(ctx context.Context, name string) string {
453 var stat unix.Stat_t
454 err := unix.Stat(name, &stat)
455 if err != nil {
456 return ""
457 }
458 major := unix.Major(uint64(stat.Rdev))
459 minor := unix.Minor(uint64(stat.Rdev))
460
461
462 udevDataPath := common.HostRun(fmt.Sprintf("udev/data/b%d:%d", major, minor))
463 if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil {
464 scanner := bufio.NewScanner(bytes.NewReader(udevdata))
465 for scanner.Scan() {
466 values := strings.Split(scanner.Text(), "=")
467 if len(values) == 2 && values[0] == "E:ID_SERIAL" {
468 return values[1]
469 }
470 }
471 }
472
473
474
475 devicePath := common.HostSys(fmt.Sprintf("dev/block/%d:0/device", major))
476 model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model"))
477 serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial"))
478 if len(model) > 0 && len(serial) > 0 {
479 return fmt.Sprintf("%s_%s", string(model), string(serial))
480 }
481 return ""
482 }
483
484
485
486
487
488 func GetLabel(name string) string {
489
490 dmname_filename := common.HostSys(fmt.Sprintf("block/%s/dm/name", name))
491
492 if !common.PathExists(dmname_filename) {
493 return ""
494 }
495
496 dmname, err := ioutil.ReadFile(dmname_filename)
497 if err != nil {
498 return ""
499 } else {
500 return strings.TrimSpace(string(dmname))
501 }
502 }
503
504 func getFsType(stat unix.Statfs_t) string {
505 t := int64(stat.Type)
506 ret, ok := fsTypeMap[t]
507 if !ok {
508 return ""
509 }
510 return ret
511 }
512
View as plain text