disk.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package stats
  2. import (
  3. "bufio"
  4. "bytes"
  5. "context"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. )
  10. // Storage represents /dev/sdXX/ctl.
  11. type Storage struct {
  12. Name string
  13. Model string
  14. Capacity int64
  15. Partitions []*Partition
  16. }
  17. // Partition represents a part of /dev/sdXX/ctl.
  18. type Partition struct {
  19. Name string
  20. Start uint64
  21. End uint64
  22. }
  23. func ReadStorages(ctx context.Context, opts ...Option) ([]*Storage, error) {
  24. cfg := newConfig(opts...)
  25. sdctl := filepath.Join(cfg.rootdir, "/dev/sdctl")
  26. f, err := os.Open(sdctl)
  27. if err != nil {
  28. return nil, err
  29. }
  30. defer f.Close()
  31. var a []*Storage
  32. scanner := bufio.NewScanner(f)
  33. for scanner.Scan() {
  34. fields := bytes.Split(scanner.Bytes(), delim)
  35. if len(fields) == 0 {
  36. continue
  37. }
  38. exp := string(fields[0]) + "*"
  39. if !strings.HasPrefix(exp, "sd") {
  40. continue
  41. }
  42. dir := filepath.Join(cfg.rootdir, "/dev", exp)
  43. m, err := filepath.Glob(dir)
  44. if err != nil {
  45. return nil, err
  46. }
  47. for _, dir := range m {
  48. s, err := readStorage(dir)
  49. if err != nil {
  50. return nil, err
  51. }
  52. a = append(a, s)
  53. }
  54. }
  55. if err := scanner.Err(); err != nil {
  56. return nil, err
  57. }
  58. return a, nil
  59. }
  60. func readStorage(dir string) (*Storage, error) {
  61. ctl := filepath.Join(dir, "ctl")
  62. f, err := os.Open(ctl)
  63. if err != nil {
  64. return nil, err
  65. }
  66. defer f.Close()
  67. var s Storage
  68. s.Name = filepath.Base(dir)
  69. scanner := bufio.NewScanner(f)
  70. for scanner.Scan() {
  71. line := scanner.Bytes()
  72. switch {
  73. case bytes.HasPrefix(line, []byte("inquiry ")):
  74. s.Model = string(bytes.TrimSpace(line[7:]))
  75. case bytes.HasPrefix(line, []byte("geometry ")):
  76. fields := bytes.Split(line, delim)
  77. if len(fields) < 3 {
  78. continue
  79. }
  80. var p intParser
  81. sec := p.ParseInt64(string(fields[1]), 10)
  82. size := p.ParseInt64(string(fields[2]), 10)
  83. if err := p.Err(); err != nil {
  84. return nil, err
  85. }
  86. s.Capacity = sec * size
  87. case bytes.HasPrefix(line, []byte("part ")):
  88. fields := bytes.Split(line, delim)
  89. if len(fields) < 4 {
  90. continue
  91. }
  92. var p intParser
  93. start := p.ParseUint64(string(fields[2]), 10)
  94. end := p.ParseUint64(string(fields[3]), 10)
  95. if err := p.Err(); err != nil {
  96. return nil, err
  97. }
  98. s.Partitions = append(s.Partitions, &Partition{
  99. Name: string(fields[1]),
  100. Start: start,
  101. End: end,
  102. })
  103. }
  104. }
  105. if err := scanner.Err(); err != nil {
  106. return nil, err
  107. }
  108. return &s, nil
  109. }