smart.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package smart
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/anatol/smart.go"
  9. )
  10. // SMART data structure for SATA disks
  11. type SATAAttrData struct {
  12. Id uint8
  13. Name string
  14. Type int
  15. RawVal uint64
  16. Current uint8
  17. Worst uint8
  18. }
  19. type SMARTData struct {
  20. ModelNumber string
  21. SerialNumber string
  22. Size uint64
  23. Temperature int
  24. /* NVME specific fields */
  25. NameSpaceUtilizations []uint64
  26. PowerOnHours uint64
  27. PowerCycles uint64
  28. UnsafeShutdowns uint64
  29. MediaErrors uint64
  30. /* SATA specific fields */
  31. SATAAttrs []*SATAAttrData
  32. }
  33. // Get SMART data of a particular disk / device
  34. func GetSMARTData(disk string) (*SMARTData, error) {
  35. if !strings.HasPrefix(disk, "/dev/") {
  36. disk = filepath.Join("/dev", disk)
  37. }
  38. //Check if the disk exists
  39. if _, err := os.Stat(disk); os.IsNotExist(err) {
  40. return nil, fmt.Errorf("disk %s does not exist", disk)
  41. }
  42. // Check if the disk is NVMe or SATA
  43. isNVMe := strings.HasPrefix(disk, "/dev/nvme")
  44. isSATA := strings.HasPrefix(disk, "/dev/sd")
  45. // If the disk is not NVMe or SATA, return an error
  46. if !isNVMe && !isSATA {
  47. return nil, fmt.Errorf("disk %s is not an NVMe or SATA disk", disk)
  48. }
  49. if isNVMe {
  50. return getNVMESMART(disk)
  51. } else if isSATA {
  52. return getSATASMART(disk)
  53. }
  54. return nil, errors.New("unsupported disk type")
  55. }
  56. // Check if the path is the disk path instead of partition path
  57. func IsRootDisk(deviceFilePath string) bool {
  58. deviceFilename := filepath.Base(deviceFilePath)
  59. if !(strings.HasPrefix(deviceFilename, "sd") || strings.HasPrefix(deviceFilename, "nvme")) {
  60. return false
  61. }
  62. if strings.HasPrefix(deviceFilename, "sd") && len(deviceFilename) > 3 {
  63. return false
  64. }
  65. if strings.HasPrefix(deviceFilename, "nvme") && len(deviceFilename) > 5 {
  66. return false
  67. }
  68. return true
  69. }
  70. // Check if this SMART implementation supports the disk type
  71. func IsDiskSupportedType(disk string) bool {
  72. return IsNVMeDevice(disk) || IsSATADevice(disk)
  73. }
  74. // Check if the disk is a SATA device
  75. func IsSATADevice(disk string) bool {
  76. if !strings.HasPrefix(disk, "/dev/") {
  77. disk = filepath.Join("/dev", disk)
  78. }
  79. _, err := smart.OpenSata(disk)
  80. return err == nil
  81. }
  82. // Check if the disk is a NVMe device
  83. func IsNVMeDevice(disk string) bool {
  84. if !strings.HasPrefix(disk, "/dev/") {
  85. disk = filepath.Join("/dev", disk)
  86. }
  87. _, err := smart.OpenNVMe(disk)
  88. return err == nil
  89. }