smart.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package smart
  2. /*
  3. DISK SMART Service Listener
  4. Original author: alanyeung
  5. Rewritten by tobychui in Oct 2020 for system arch upgrade
  6. This module is not the core part of aroz online system.
  7. If you want to remove disk smart handler (e.g. running in VM?)
  8. remove the corrisponding code in disk.go
  9. */
  10. import (
  11. "encoding/json"
  12. "log"
  13. "net/http"
  14. "strings"
  15. //"os/exec"
  16. "errors"
  17. "runtime"
  18. //"time"
  19. )
  20. type SMARTListener struct {
  21. SystemSmartExecutable string
  22. DriveList DevicesList `json:"driveList"`
  23. }
  24. // DiskSmartInit Desktop script initiation
  25. func NewSmartListener() (*SMARTListener, error) {
  26. smartExec := getBinary()
  27. log.Println("Starting SMART mointoring")
  28. if smartExec == "" {
  29. return &SMARTListener{}, errors.New("not supported platform")
  30. }
  31. if !(fileExists(smartExec)) {
  32. return &SMARTListener{}, errors.New("smartctl not found")
  33. }
  34. driveList := scanAvailableDevices(smartExec)
  35. readSMARTDevices(smartExec, &driveList)
  36. fillHealthyStatus(&driveList)
  37. return &SMARTListener{
  38. SystemSmartExecutable: smartExec,
  39. DriveList: driveList,
  40. }, nil
  41. }
  42. func scanAvailableDevices(smartExec string) DevicesList {
  43. rawInfo := execCommand(smartExec, "--scan", "--json=c")
  44. devicesList := new(DevicesList)
  45. json.Unmarshal([]byte(rawInfo), &devicesList)
  46. //used to remove csmi devices (Intel RAID Devices)
  47. numOfRemoved := 0
  48. for i, device := range devicesList.Devices {
  49. if strings.Contains(device.Name, "/dev/csmi") {
  50. devicesList.Devices = append(devicesList.Devices[:i-numOfRemoved], devicesList.Devices[i+1-numOfRemoved:]...)
  51. numOfRemoved++
  52. }
  53. }
  54. return *devicesList
  55. }
  56. func readSMARTDevices(smartExec string, devicesList *DevicesList) {
  57. for i, device := range devicesList.Devices {
  58. rawInfo := execCommand(smartExec, device.Name, "--info", "--all", "--json=c")
  59. deviceSMART := new(DeviceSMART)
  60. json.Unmarshal([]byte(rawInfo), &deviceSMART)
  61. devicesList.Devices[i].Smart = *deviceSMART
  62. }
  63. }
  64. func fillHealthyStatus(devicesList *DevicesList) {
  65. devicesList.Healthy = "Normal"
  66. for i, device := range devicesList.Devices {
  67. for j, smartTableElement := range device.Smart.AtaSmartAttributes.Table {
  68. devicesList.Devices[i].Smart.Healthy = "Normal"
  69. devicesList.Devices[i].Smart.AtaSmartAttributes.Table[j].Healthy = "Normal"
  70. if smartTableElement.WhenFailed == "FAILING_NOW" {
  71. devicesList.Devices[i].Smart.AtaSmartAttributes.Table[j].Healthy = "Failing"
  72. devicesList.Devices[i].Smart.Healthy = "Failing"
  73. devicesList.Healthy = "Failing"
  74. break
  75. }
  76. if smartTableElement.WhenFailed == "In_the_past" {
  77. devicesList.Devices[i].Smart.AtaSmartAttributes.Table[j].Healthy = "Attention"
  78. devicesList.Devices[i].Smart.Healthy = "Attention"
  79. devicesList.Healthy = "Attention"
  80. break
  81. }
  82. }
  83. }
  84. }
  85. func (s *SMARTListener) GetSMART(w http.ResponseWriter, r *http.Request) {
  86. jsonText, _ := json.Marshal(s.DriveList)
  87. sendJSONResponse(w, string(jsonText))
  88. }
  89. func getBinary() string {
  90. if runtime.GOOS == "windows" {
  91. return ".\\system\\disk\\smart\\win\\smartctl.exe"
  92. } else if runtime.GOOS == "linux" {
  93. if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
  94. return "./system/disk/smart/linux/smartctl_armv6"
  95. }
  96. if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
  97. return "./system/disk/smart/linux/smartctl_i386"
  98. }
  99. }
  100. return ""
  101. }