-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
102 lines (88 loc) · 2.72 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//go:generate bash ./g_version.sh
package main
import (
"bytes"
"fmt"
"log"
"log/syslog"
"os"
"os/exec"
"path"
"strings"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
appName = path.Base(os.Args[0])
app = kingpin.New(appName, "A command-line checker for Disk Health checks using smartctl, by CrossEngage")
checkName = app.Flag("name", "check name").Default(appName).String()
debug = app.Flag("debug", "if set, enables debug logs").Default("false").Bool()
stderr = app.Flag("stderr", "if set, enables logging to stderr instead of syslog").Default("false").Bool()
smartCtl = app.Flag("smartctl", "Path of smartctl").Default("/usr/sbin/smartctl").String()
// https://en.wikipedia.org/wiki/S.M.A.R.T.#Known_ATA_S.M.A.R.T._attributes
attrIDs = app.Flag("attrs", "SMART Attribute IDs to return").Default(
"1", "2", "3", "5", "7", "8", "9", "10", "12", "171", "172", "173",
"174", "190", "194", "197", "198", "199", "231", "233").Ints()
)
func main() {
app.Version(version)
kingpin.MustParse(app.Parse(os.Args[1:]))
if *stderr {
log.SetOutput(os.Stderr)
} else {
slog, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_DAEMON, appName)
if err != nil {
log.Fatal(err)
}
log.SetOutput(slog)
}
hostname, err := os.Hostname()
if err != nil {
log.Fatal(err)
}
stdOut, _, err := smartctl(*debug, "--scan")
if err != nil {
log.Fatal(err)
}
devices := parseSMARTCtlScan(stdOut)
for _, device := range devices {
stdOut, _, err := smartctl(*debug, "-i", "-H", device.Path, "-d", device.Type)
if err != nil {
log.Println(err)
}
info := parseSMARTCtlInfo(stdOut)
fmt.Printf("%s,host=%s,disk=%s,type=%s ", *checkName, hostname, device.Path, strings.Replace(device.Type, ",", "_", -1))
values := []string{fmt.Sprintf(`disk_status="%s"`, info.Health)}
if info.SMARTSupport {
stdOut, _, err = smartctl(*debug, "-A", device.Path, "-d", device.Type)
if err != nil {
log.Println(err)
}
attrs := parseAttributeList(stdOut)
for _, attr := range attrs {
// TODO replace this by something more efficient
for _, id := range *attrIDs {
if attr.ID == id {
values = append(values, attr.String(true, false))
continue
}
}
}
}
fmt.Println(strings.Join(values, ","))
}
}
func smartctl(debug bool, args ...string) (string, string, error) {
cmd := exec.Command(*smartCtl, args...)
if debug {
log.Printf("Running `%s with args: %v", *smartCtl, args)
}
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
if debug {
log.Printf("%s: stdout `%s`, stderr `%s`", *smartCtl, strings.TrimSpace(outStr), strings.TrimSpace(errStr))
}
return outStr, errStr, err
}