1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package sysfs
18
19 import (
20 "os"
21 "path/filepath"
22 "regexp"
23
24 "github.com/prometheus/procfs/internal/util"
25 )
26
27 const (
28 sasDeviceClassPath = "class/sas_device"
29 sasEndDeviceClassPath = "class/sas_end_device"
30 sasExpanderClassPath = "class/sas_expander"
31 )
32
33 type SASDevice struct {
34 Name string
35 SASAddress string
36 SASPhys []string
37 SASPorts []string
38 BlockDevices []string
39 }
40
41 type SASDeviceClass map[string]*SASDevice
42
43 var (
44 sasTargetDeviceRegexp = regexp.MustCompile(`^target[0-9:]+$`)
45 sasTargetSubDeviceRegexp = regexp.MustCompile(`[0-9]+:.*`)
46 )
47
48
49
50
51
52 func (fs FS) parseSASDeviceClass(dir string) (SASDeviceClass, error) {
53 path := fs.sys.Path(dir)
54
55 dirs, err := os.ReadDir(path)
56 if err != nil {
57 return nil, err
58 }
59
60 sdc := make(SASDeviceClass, len(dirs))
61
62 for _, d := range dirs {
63 device, err := fs.parseSASDevice(d.Name())
64 if err != nil {
65 return nil, err
66 }
67
68 sdc[device.Name] = device
69 }
70
71 return sdc, nil
72 }
73
74
75 func (fs FS) SASDeviceClass() (SASDeviceClass, error) {
76 return fs.parseSASDeviceClass(sasDeviceClassPath)
77 }
78
79
80
81 func (fs FS) SASEndDeviceClass() (SASDeviceClass, error) {
82 return fs.parseSASDeviceClass(sasEndDeviceClassPath)
83 }
84
85
86
87 func (fs FS) SASExpanderClass() (SASDeviceClass, error) {
88 return fs.parseSASDeviceClass(sasExpanderClassPath)
89 }
90
91
92
93
94 func (fs FS) parseSASDevice(name string) (*SASDevice, error) {
95 device := SASDevice{Name: name}
96
97 devicepath := fs.sys.Path(filepath.Join(sasDeviceClassPath, name, "device"))
98
99 dirs, err := os.ReadDir(devicepath)
100 if err != nil {
101 return nil, err
102 }
103
104 for _, d := range dirs {
105 if sasPhyDeviceRegexp.MatchString(d.Name()) {
106 device.SASPhys = append(device.SASPhys, d.Name())
107 }
108 if sasPortDeviceRegexp.MatchString(d.Name()) {
109 device.SASPorts = append(device.SASPorts, d.Name())
110 }
111 }
112
113 address := fs.sys.Path(sasDeviceClassPath, name, "sas_address")
114 value, err := util.SysReadFile(address)
115 if err != nil {
116 return nil, err
117 }
118 device.SASAddress = value
119
120 device.BlockDevices, err = fs.blockSASDeviceBlockDevices(name)
121 if err != nil {
122 return nil, err
123 }
124
125 return &device, nil
126 }
127
128
129
130
131
132
133
134
135
136 func (fs FS) blockSASDeviceBlockDevices(name string) ([]string, error) {
137 var devices []string
138
139 devicepath := fs.sys.Path(filepath.Join(sasDeviceClassPath, name, "device"))
140
141 dirs, err := os.ReadDir(devicepath)
142 if err != nil {
143 return nil, err
144 }
145
146 for _, d := range dirs {
147 if sasTargetDeviceRegexp.MatchString(d.Name()) {
148 targetdir := d.Name()
149
150 subtargets, err := os.ReadDir(filepath.Join(devicepath, targetdir))
151 if err != nil {
152 return nil, err
153 }
154
155 for _, targetsubdir := range subtargets {
156
157 if !sasTargetSubDeviceRegexp.MatchString(targetsubdir.Name()) {
158
159 continue
160 }
161
162 blocks, err := os.ReadDir(filepath.Join(devicepath, targetdir, targetsubdir.Name(), "block"))
163 if err != nil {
164 if os.IsNotExist(err) {
165 continue
166 }
167 return nil, err
168 }
169
170 for _, blockdevice := range blocks {
171 devices = append(devices, blockdevice.Name())
172 }
173 }
174 }
175 }
176
177 return devices, nil
178 }
179
180
181 func (sdc *SASDeviceClass) GetByName(name string) *SASDevice {
182 return (*sdc)[name]
183 }
184
185
186 func (sdc *SASDeviceClass) GetByPhy(name string) *SASDevice {
187 for _, d := range *sdc {
188 for _, p := range d.SASPhys {
189 if p == name {
190 return d
191 }
192 }
193 }
194 return nil
195 }
196
197
198 func (sdc *SASDeviceClass) GetByPort(name string) *SASDevice {
199 for _, d := range *sdc {
200 for _, p := range d.SASPorts {
201 if p == name {
202 return d
203 }
204 }
205 }
206 return nil
207 }
208
View as plain text