mirror of
https://github.com/henrygd/beszel.git
synced 2025-12-17 02:36:17 +01:00
@@ -5,7 +5,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -23,6 +25,7 @@ type SmartManager struct {
|
|||||||
SmartDevices []*DeviceInfo
|
SmartDevices []*DeviceInfo
|
||||||
refreshMutex sync.Mutex
|
refreshMutex sync.Mutex
|
||||||
lastScanTime time.Time
|
lastScanTime time.Time
|
||||||
|
binPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type scanOutput struct {
|
type scanOutput struct {
|
||||||
@@ -160,7 +163,7 @@ func (sm *SmartManager) ScanDevices(force bool) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, "smartctl", "--scan", "-j")
|
cmd := exec.CommandContext(ctx, sm.binPath, "--scan", "-j")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -382,7 +385,7 @@ func (sm *SmartManager) CollectSmart(deviceInfo *DeviceInfo) error {
|
|||||||
|
|
||||||
// Try with -n standby first if we have existing data
|
// Try with -n standby first if we have existing data
|
||||||
args := sm.smartctlArgs(deviceInfo, true)
|
args := sm.smartctlArgs(deviceInfo, true)
|
||||||
cmd := exec.CommandContext(ctx, "smartctl", args...)
|
cmd := exec.CommandContext(ctx, sm.binPath, args...)
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
// Check if device is in standby (exit status 2)
|
// Check if device is in standby (exit status 2)
|
||||||
@@ -395,7 +398,7 @@ func (sm *SmartManager) CollectSmart(deviceInfo *DeviceInfo) error {
|
|||||||
ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer cancel2()
|
defer cancel2()
|
||||||
args = sm.smartctlArgs(deviceInfo, false)
|
args = sm.smartctlArgs(deviceInfo, false)
|
||||||
cmd = exec.CommandContext(ctx2, "smartctl", args...)
|
cmd = exec.CommandContext(ctx2, sm.binPath, args...)
|
||||||
output, err = cmd.CombinedOutput()
|
output, err = cmd.CombinedOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -875,13 +878,24 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// detectSmartctl checks if smartctl is installed, returns an error if not
|
// detectSmartctl checks if smartctl is installed, returns an error if not
|
||||||
func (sm *SmartManager) detectSmartctl() error {
|
func (sm *SmartManager) detectSmartctl() (string, error) {
|
||||||
if _, err := exec.LookPath("smartctl"); err == nil {
|
if path, err := exec.LookPath("smartctl"); err == nil {
|
||||||
slog.Debug("smartctl found")
|
return path, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
slog.Debug("smartctl not found")
|
locations := []string{}
|
||||||
return errors.New("smartctl not found")
|
if runtime.GOOS == "windows" {
|
||||||
|
locations = append(locations,
|
||||||
|
"C:\\Program Files\\smartmontools\\bin\\smartctl.exe",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
locations = append(locations, "/opt/homebrew/bin/smartctl")
|
||||||
|
}
|
||||||
|
for _, location := range locations {
|
||||||
|
if _, err := os.Stat(location); err == nil {
|
||||||
|
return location, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("smartctl not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSmartManager creates and initializes a new SmartManager
|
// NewSmartManager creates and initializes a new SmartManager
|
||||||
@@ -889,9 +903,12 @@ func NewSmartManager() (*SmartManager, error) {
|
|||||||
sm := &SmartManager{
|
sm := &SmartManager{
|
||||||
SmartDataMap: make(map[string]*smart.SmartData),
|
SmartDataMap: make(map[string]*smart.SmartData),
|
||||||
}
|
}
|
||||||
if err := sm.detectSmartctl(); err != nil {
|
path, err := sm.detectSmartctl()
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
slog.Debug("smartctl", "path", path)
|
||||||
|
sm.binPath = path
|
||||||
return sm, nil
|
return sm, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user