-
Notifications
You must be signed in to change notification settings - Fork 0
/
diskdevice.go
156 lines (137 loc) · 3.48 KB
/
diskdevice.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package drivelist
import (
"bytes"
"io"
"os"
"strconv"
"strings"
"github.com/golang/glog"
)
type DiskDevice struct {
DeviceName string
Devices []string // Names in /dev that refer to this disk
WWN string
SysPath string
Model string
Serial string
Attribs map[string]string
Uses []string
GenericDevice string
// SCSI path
// Want host -> enclosure... -> end_device, with PHY info along the way.
// Enclosure data
Expander string
ExpanderPath string
EnclosureBay string
// Size
Size uint64 // bytes
}
func NewDiskDevice(name string) (*DiskDevice, error) {
d := &DiskDevice{}
u, err := GetUdevAdmData(name)
if err != nil {
return d, err
}
d.Attribs = u.Attribs
d.DeviceName = u.DeviceName
d.SysPath = "/sys" + d.Attribs["DEVPATH"]
d.WWN = d.Attribs["ID_WWN"]
d.Model = d.Attribs["ID_MODEL"]
d.Serial = d.Attribs["SCSI_IDENT_SERIAL"]
d.Uses = []string{}
d.Devices = []string{"/dev/" + d.DeviceName} // Add /dev/sdX
for _, i := range strings.Split(d.Attribs["DEVLINKS"], " ") {
d.Devices = append(d.Devices, i)
}
err = d.PopulateSESData()
if err != nil {
return d, err
}
sizeString, err := os.ReadFile("/sys/class/block/" + d.DeviceName + "/size")
if err != nil {
glog.Errorf("Error reading file: %v\n", err)
} else {
sizeBlocks, _ := strconv.ParseUint(strings.TrimSuffix(string(sizeString), "\n"), 10, 64)
d.Size = sizeBlocks * 512
}
return d, nil
}
func NewEmptyBayDiskDevice(expander string, expanderPath string, bay string) (*DiskDevice, error) {
d := &DiskDevice{}
d.Expander = expander
d.ExpanderPath = expanderPath
d.EnclosureBay = bay
d.Uses = []string{"empty"} // Maybe?
return d, nil
}
func (d *DiskDevice) PopulateSESData() error {
var prefix, endDevice, endDevicePath string
syspath := strings.Split(d.SysPath, "/")
for _, p := range syspath {
prefix += "/" + p
if strings.HasPrefix(p, "expander-") {
d.Expander = p
d.ExpanderPath = prefix
}
if strings.HasPrefix(p, "end_device-") {
endDevice = p
endDevicePath = prefix
d.GenericDevice = "/dev/bsg/" + endDevice
}
}
if endDevice != "" {
// Bay info should be in endDevicePath/sas_device/endDevice/bay_identifier
bay, err := os.ReadFile(endDevicePath + "/sas_device/" + endDevice + "/bay_identifier")
if err == nil {
d.EnclosureBay = strings.TrimSuffix(string(bay), "\n")
}
}
return nil
}
func (d *DiskDevice) WriteTabs(w io.Writer) {
buf := bytes.Buffer{}
for _, f := range FieldFlag {
switch f {
case "devicename":
buf.WriteString(d.DeviceName)
buf.WriteString("\t")
case "devices":
buf.WriteString(strings.Join(d.Devices, ","))
buf.WriteString("\t")
case "wwn":
buf.WriteString(d.WWN)
buf.WriteString("\t")
case "syspath":
buf.WriteString(d.SysPath)
buf.WriteString("\t")
case "model":
buf.WriteString(d.Model)
buf.WriteString("\t")
case "serial":
buf.WriteString(d.Serial)
buf.WriteString("\t")
case "uses":
buf.WriteString(strings.Join(d.Uses, ","))
buf.WriteString("\t")
case "genericdevice":
buf.WriteString(d.GenericDevice)
buf.WriteString("\t")
case "expander":
buf.WriteString(d.Expander)
buf.WriteString("\t")
case "expanderpath":
buf.WriteString(d.ExpanderPath)
buf.WriteString("\t")
case "bay":
buf.WriteString(d.EnclosureBay)
buf.WriteString("\t")
case "size":
buf.WriteString(FormatDiskSize(d.Size))
buf.WriteString("\t")
default:
panic("unknown field")
}
}
buf.WriteString("\n")
buf.WriteTo(w)
}