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}