master
1package get
2
3import (
4 "fmt"
5 "os"
6 "reflect"
7 "runtime"
8
9 "github.com/anatol/smart.go"
10 "github.com/jedib0t/go-pretty/v6/table"
11 "github.com/kahnwong/swissknife/configs/color"
12 "github.com/shirou/gopsutil/v4/disk"
13)
14
15func nvmeSmart(device string) error {
16 var err error
17 dev, err := smart.OpenNVMe(device)
18 if err != nil {
19 return err
20 } else {
21 sm, err := dev.ReadSMART()
22 if err != nil {
23 return err
24 }
25
26 // render table
27 t := table.NewWriter()
28 t.SetOutputMirror(os.Stdout)
29 t.AppendHeader(table.Row{"Name", "Value"})
30
31 v := reflect.ValueOf(sm)
32 typeOfS := v.Type()
33
34 if v.Kind() == reflect.Ptr {
35 v = v.Elem()
36 typeOfS = typeOfS.Elem()
37 }
38
39 for i := 0; i < v.NumField(); i++ {
40 fieldName := typeOfS.Field(i).Name
41 field := v.Field(i)
42
43 if !field.CanInterface() {
44 continue
45 } else {
46 fieldValue := field.Interface()
47
48 t.AppendRows([]table.Row{
49 {
50 color.Green(fieldName),
51 fieldValue,
52 },
53 })
54 }
55 }
56
57 t.Render()
58
59 return nil
60 }
61}
62
63func sataSmart(device string) error {
64 var err error
65 dev, err := smart.OpenSata(device)
66 if err != nil {
67 return err
68 } else {
69 sm, err := dev.ReadSMARTData()
70 if err != nil {
71 return err
72 }
73
74 // render table
75 t := table.NewWriter()
76 t.SetOutputMirror(os.Stdout)
77 t.AppendHeader(table.Row{"Name", "Current", "Worst", "Raw Value"})
78
79 for _, i := range sm.Attrs {
80 t.AppendRows([]table.Row{
81 {
82 color.Green(i.Name),
83 i.Current,
84 i.Worst,
85 i.ValueRaw,
86 },
87 })
88 }
89
90 t.Render()
91
92 return nil
93 }
94}
95
96func Smart(args []string) error {
97 if runtime.GOOS != "linux" {
98 return fmt.Errorf("%s is not supported", runtime.GOOS)
99 }
100
101 var device string
102 var err error
103 if len(args) == 0 {
104 device, err = getRootDiskVolume()
105 if err != nil {
106 return err
107 }
108 } else if len(args) == 1 {
109 device = args[0]
110 } else {
111 return fmt.Errorf("too many arguments")
112 }
113
114 err = nvmeSmart(device)
115 if err != nil {
116 err = sataSmart(device)
117 if err != nil {
118 return fmt.Errorf("unrecognized device type. It's not NVME or SATA, or you didn't run as sudo: %w", err)
119 }
120 }
121 return nil
122}
123
124func getRootDiskVolume() (string, error) {
125 partitions, err := disk.Partitions(false)
126 if err != nil {
127 return "", fmt.Errorf("failed to get disk partitions: %w", err)
128 }
129
130 var volume string
131 for _, partition := range partitions {
132 if partition.Mountpoint == "/" {
133 volume = partition.Device
134 }
135 }
136
137 return volume, nil
138}