This commit is contained in:
lukas 2022-04-15 17:16:15 +02:00
commit 7499595649
4 changed files with 183 additions and 0 deletions

36
disks.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"encoding/json"
"fmt"
"log"
)
func getDisks() *Devices {
rawout := execSystem("lsblk", "-dJ", "-I 8")
if rawout == nil {
log.Fatal("")
}
var parsed Devices
// decoding country1 struct
// from json format
err := json.Unmarshal(rawout, &parsed)
if err != nil {
// if error is not nil
// print error
fmt.Println(err)
}
return &parsed
}
type BlockDevice struct {
Name string `json:"name"`
Size string `json:"size"`
Type string `json:"type"`
}
type Devices struct {
Blockdevices []BlockDevice `json:"blockdevices"`
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module diskhealth
go 1.16

43
main.go Normal file
View File

@ -0,0 +1,43 @@
package main
import (
"bytes"
"fmt"
"log"
"os/exec"
"strings"
)
func execSystem(cmd string, args ...string) []byte {
com := exec.Command(cmd, args...)
var out bytes.Buffer
com.Stdout = &out
com.Stderr = &out
err := com.Run()
if out.Bytes() == nil {
fmt.Println(out.String())
log.Fatal(err)
return nil
}
return out.Bytes()
}
func main() {
fmt.Println("Running smart check on all disks")
disks := getDisks()
for _, blockdevice := range disks.Blockdevices {
fmt.Printf("\nChecking /dev/%s\n", blockdevice.Name)
path := fmt.Sprintf("/dev/%s", blockdevice.Name)
info := getDiskInfo(path)
fmt.Printf("%s %s\n", info.ModelFamily, info.ModelName)
checkSmartAttributes(path, strings.Contains(strings.ToLower(info.ModelName+info.ModelFamily), strings.ToLower("Seagate")), info.RotationRate != 0)
}
}

101
smartdiskinfo.go Normal file
View File

@ -0,0 +1,101 @@
package main
import (
"encoding/json"
"fmt"
)
type DiskInfo struct {
ModelFamily string `json:"model_family"`
ModelName string `json:"model_name"`
SerialNumber string `json:"serial_number"`
RotationRate uint `json:"rotation_rate"`
}
func getDiskInfo(diskpath string) *DiskInfo {
rawsmart := execSystem("smartctl", "-i", "-json", diskpath)
if rawsmart == nil {
fmt.Println("error while getting smart info")
}
var info DiskInfo
// decoding country1 struct
// from json format
err := json.Unmarshal(rawsmart, &info)
if err != nil {
fmt.Println(err)
}
return &info
}
type Item struct {
Name string `json:"name"`
Raw struct {
Value uint64 `json:"value"`
} `json:"raw"`
}
func checkSmartAttributes(diskpath string, isSeagate bool, isHdd bool) {
rawsmart := execSystem("smartctl", "-A", "-json", diskpath)
if rawsmart == nil {
fmt.Println("error while getting smart info")
}
type RawAttr struct {
AtaSmartAttr struct {
Table []Item `json:"table"`
} `json:"ata_smart_attributes"`
}
var rawattr RawAttr
err := json.Unmarshal(rawsmart, &rawattr)
if err != nil {
fmt.Println(err)
}
rrerrrate := getItemValue(rawattr.AtaSmartAttr.Table, "Raw_Read_Error_Rate")
// seagate hdds have a special way to represent their error rates
if isSeagate {
// [--16bits---|---32bits---]
// error count| operation count
rrerrrate = rrerrrate >> 32
}
fmt.Println("Raw_Read_Error_Rate: " + evalStrZero(rrerrrate))
fmt.Println("Reallocated_Sector_Ct: " + evalStrZero(getItemValue(rawattr.AtaSmartAttr.Table, "Reallocated_Sector_Ct")))
// there are some additinoal hdd smart values
if isHdd {
rrerrrate = getItemValue(rawattr.AtaSmartAttr.Table, "Seek_Error_Rate")
if isSeagate {
// [--16bits---|---32bits---]
// error count| operation count
rrerrrate = rrerrrate >> 32
}
fmt.Println("Seek_Error_Rate: " + evalStrZero(rrerrrate))
fmt.Println("Spin_Retry_Count: " + evalStrZero(getItemValue(rawattr.AtaSmartAttr.Table, "Spin_Retry_Count")))
fmt.Println("Spin_Up_Time: " + evalStrZero(getItemValue(rawattr.AtaSmartAttr.Table, "Spin_Up_Time")))
}
fmt.Println(rawattr)
}
func evalStrZero(nr uint64) string {
if nr == 0 {
return "\tPASS"
} else {
return fmt.Sprintf("\tFAIL :: raw value=%d", nr)
}
}
func getItemValue(arr []Item, name string) uint64 {
for i := range arr {
if arr[i].Name == name {
return arr[i].Raw.Value
}
}
return 0
}