1// Copyright 2018 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// +build !windows
15
16package sysfs
17
18import (
19	"fmt"
20	"io/ioutil"
21	"os"
22	"path/filepath"
23
24	"github.com/prometheus/procfs/internal/util"
25)
26
27// PowerSupply contains info from files in /sys/class/power_supply for a
28// single power supply.
29type PowerSupply struct {
30	Name                     string // Power Supply Name
31	Authentic                *int64 // /sys/class/power_supply/<Name>/authentic
32	Calibrate                *int64 // /sys/class/power_supply/<Name>/calibrate
33	Capacity                 *int64 // /sys/class/power_supply/<Name>/capacity
34	CapacityAlertMax         *int64 // /sys/class/power_supply/<Name>/capacity_alert_max
35	CapacityAlertMin         *int64 // /sys/class/power_supply/<Name>/capacity_alert_min
36	CapacityLevel            string // /sys/class/power_supply/<Name>/capacity_level
37	ChargeAvg                *int64 // /sys/class/power_supply/<Name>/charge_avg
38	ChargeControlLimit       *int64 // /sys/class/power_supply/<Name>/charge_control_limit
39	ChargeControlLimitMax    *int64 // /sys/class/power_supply/<Name>/charge_control_limit_max
40	ChargeCounter            *int64 // /sys/class/power_supply/<Name>/charge_counter
41	ChargeEmpty              *int64 // /sys/class/power_supply/<Name>/charge_empty
42	ChargeEmptyDesign        *int64 // /sys/class/power_supply/<Name>/charge_empty_design
43	ChargeFull               *int64 // /sys/class/power_supply/<Name>/charge_full
44	ChargeFullDesign         *int64 // /sys/class/power_supply/<Name>/charge_full_design
45	ChargeNow                *int64 // /sys/class/power_supply/<Name>/charge_now
46	ChargeTermCurrent        *int64 // /sys/class/power_supply/<Name>/charge_term_current
47	ChargeType               string // /sys/class/power_supply/<Name>/charge_type
48	ConstantChargeCurrent    *int64 // /sys/class/power_supply/<Name>/constant_charge_current
49	ConstantChargeCurrentMax *int64 // /sys/class/power_supply/<Name>/constant_charge_current_max
50	ConstantChargeVoltage    *int64 // /sys/class/power_supply/<Name>/constant_charge_voltage
51	ConstantChargeVoltageMax *int64 // /sys/class/power_supply/<Name>/constant_charge_voltage_max
52	CurrentAvg               *int64 // /sys/class/power_supply/<Name>/current_avg
53	CurrentBoot              *int64 // /sys/class/power_supply/<Name>/current_boot
54	CurrentMax               *int64 // /sys/class/power_supply/<Name>/current_max
55	CurrentNow               *int64 // /sys/class/power_supply/<Name>/current_now
56	CycleCount               *int64 // /sys/class/power_supply/<Name>/cycle_count
57	EnergyAvg                *int64 // /sys/class/power_supply/<Name>/energy_avg
58	EnergyEmpty              *int64 // /sys/class/power_supply/<Name>/energy_empty
59	EnergyEmptyDesign        *int64 // /sys/class/power_supply/<Name>/energy_empty_design
60	EnergyFull               *int64 // /sys/class/power_supply/<Name>/energy_full
61	EnergyFullDesign         *int64 // /sys/class/power_supply/<Name>/energy_full_design
62	EnergyNow                *int64 // /sys/class/power_supply/<Name>/energy_now
63	Health                   string // /sys/class/power_supply/<Name>/health
64	InputCurrentLimit        *int64 // /sys/class/power_supply/<Name>/input_current_limit
65	Manufacturer             string // /sys/class/power_supply/<Name>/manufacturer
66	ModelName                string // /sys/class/power_supply/<Name>/model_name
67	Online                   *int64 // /sys/class/power_supply/<Name>/online
68	PowerAvg                 *int64 // /sys/class/power_supply/<Name>/power_avg
69	PowerNow                 *int64 // /sys/class/power_supply/<Name>/power_now
70	PrechargeCurrent         *int64 // /sys/class/power_supply/<Name>/precharge_current
71	Present                  *int64 // /sys/class/power_supply/<Name>/present
72	Scope                    string // /sys/class/power_supply/<Name>/scope
73	SerialNumber             string // /sys/class/power_supply/<Name>/serial_number
74	Status                   string // /sys/class/power_supply/<Name>/status
75	Technology               string // /sys/class/power_supply/<Name>/technology
76	Temp                     *int64 // /sys/class/power_supply/<Name>/temp
77	TempAlertMax             *int64 // /sys/class/power_supply/<Name>/temp_alert_max
78	TempAlertMin             *int64 // /sys/class/power_supply/<Name>/temp_alert_min
79	TempAmbient              *int64 // /sys/class/power_supply/<Name>/temp_ambient
80	TempAmbientMax           *int64 // /sys/class/power_supply/<Name>/temp_ambient_max
81	TempAmbientMin           *int64 // /sys/class/power_supply/<Name>/temp_ambient_min
82	TempMax                  *int64 // /sys/class/power_supply/<Name>/temp_max
83	TempMin                  *int64 // /sys/class/power_supply/<Name>/temp_min
84	TimeToEmptyAvg           *int64 // /sys/class/power_supply/<Name>/time_to_empty_avg
85	TimeToEmptyNow           *int64 // /sys/class/power_supply/<Name>/time_to_empty_now
86	TimeToFullAvg            *int64 // /sys/class/power_supply/<Name>/time_to_full_avg
87	TimeToFullNow            *int64 // /sys/class/power_supply/<Name>/time_to_full_now
88	Type                     string // /sys/class/power_supply/<Name>/type
89	UsbType                  string // /sys/class/power_supply/<Name>/usb_type
90	VoltageAvg               *int64 // /sys/class/power_supply/<Name>/voltage_avg
91	VoltageBoot              *int64 // /sys/class/power_supply/<Name>/voltage_boot
92	VoltageMax               *int64 // /sys/class/power_supply/<Name>/voltage_max
93	VoltageMaxDesign         *int64 // /sys/class/power_supply/<Name>/voltage_max_design
94	VoltageMin               *int64 // /sys/class/power_supply/<Name>/voltage_min
95	VoltageMinDesign         *int64 // /sys/class/power_supply/<Name>/voltage_min_design
96	VoltageNow               *int64 // /sys/class/power_supply/<Name>/voltage_now
97	VoltageOCV               *int64 // /sys/class/power_supply/<Name>/voltage_ocv
98}
99
100// PowerSupplyClass is a collection of every power supply in
101// /sys/class/power_supply.
102//
103// The map keys are the names of the power supplies.
104type PowerSupplyClass map[string]PowerSupply
105
106// PowerSupplyClass returns info for all power supplies read from
107// /sys/class/power_supply.
108func (fs FS) PowerSupplyClass() (PowerSupplyClass, error) {
109	path := fs.sys.Path("class/power_supply")
110
111	dirs, err := ioutil.ReadDir(path)
112	if err != nil {
113		return nil, err
114	}
115
116	psc := make(PowerSupplyClass, len(dirs))
117	for _, d := range dirs {
118		ps, err := parsePowerSupply(filepath.Join(path, d.Name()))
119		if err != nil {
120			return nil, err
121		}
122
123		ps.Name = d.Name()
124		psc[d.Name()] = *ps
125	}
126
127	return psc, nil
128}
129
130func parsePowerSupply(path string) (*PowerSupply, error) {
131	files, err := ioutil.ReadDir(path)
132	if err != nil {
133		return nil, err
134	}
135
136	var ps PowerSupply
137	for _, f := range files {
138		if !f.Mode().IsRegular() {
139			continue
140		}
141
142		name := filepath.Join(path, f.Name())
143		value, err := util.SysReadFile(name)
144		if err != nil {
145			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
146				continue
147			}
148			return nil, fmt.Errorf("failed to read file %q: %v", name, err)
149		}
150
151		vp := util.NewValueParser(value)
152
153		switch f.Name() {
154		case "authentic":
155			ps.Authentic = vp.PInt64()
156		case "calibrate":
157			ps.Calibrate = vp.PInt64()
158		case "capacity":
159			ps.Capacity = vp.PInt64()
160		case "capacity_alert_max":
161			ps.CapacityAlertMax = vp.PInt64()
162		case "capacity_alert_min":
163			ps.CapacityAlertMin = vp.PInt64()
164		case "capacity_level":
165			ps.CapacityLevel = value
166		case "charge_avg":
167			ps.ChargeAvg = vp.PInt64()
168		case "charge_control_limit":
169			ps.ChargeControlLimit = vp.PInt64()
170		case "charge_control_limit_max":
171			ps.ChargeControlLimitMax = vp.PInt64()
172		case "charge_counter":
173			ps.ChargeCounter = vp.PInt64()
174		case "charge_empty":
175			ps.ChargeEmpty = vp.PInt64()
176		case "charge_empty_design":
177			ps.ChargeEmptyDesign = vp.PInt64()
178		case "charge_full":
179			ps.ChargeFull = vp.PInt64()
180		case "charge_full_design":
181			ps.ChargeFullDesign = vp.PInt64()
182		case "charge_now":
183			ps.ChargeNow = vp.PInt64()
184		case "charge_term_current":
185			ps.ChargeTermCurrent = vp.PInt64()
186		case "charge_type":
187			ps.ChargeType = value
188		case "constant_charge_current":
189			ps.ConstantChargeCurrent = vp.PInt64()
190		case "constant_charge_current_max":
191			ps.ConstantChargeCurrentMax = vp.PInt64()
192		case "constant_charge_voltage":
193			ps.ConstantChargeVoltage = vp.PInt64()
194		case "constant_charge_voltage_max":
195			ps.ConstantChargeVoltageMax = vp.PInt64()
196		case "current_avg":
197			ps.CurrentAvg = vp.PInt64()
198		case "current_boot":
199			ps.CurrentBoot = vp.PInt64()
200		case "current_max":
201			ps.CurrentMax = vp.PInt64()
202		case "current_now":
203			ps.CurrentNow = vp.PInt64()
204		case "cycle_count":
205			ps.CycleCount = vp.PInt64()
206		case "energy_avg":
207			ps.EnergyAvg = vp.PInt64()
208		case "energy_empty":
209			ps.EnergyEmpty = vp.PInt64()
210		case "energy_empty_design":
211			ps.EnergyEmptyDesign = vp.PInt64()
212		case "energy_full":
213			ps.EnergyFull = vp.PInt64()
214		case "energy_full_design":
215			ps.EnergyFullDesign = vp.PInt64()
216		case "energy_now":
217			ps.EnergyNow = vp.PInt64()
218		case "health":
219			ps.Health = value
220		case "input_current_limit":
221			ps.InputCurrentLimit = vp.PInt64()
222		case "manufacturer":
223			ps.Manufacturer = value
224		case "model_name":
225			ps.ModelName = value
226		case "online":
227			ps.Online = vp.PInt64()
228		case "power_avg":
229			ps.PowerAvg = vp.PInt64()
230		case "power_now":
231			ps.PowerNow = vp.PInt64()
232		case "precharge_current":
233			ps.PrechargeCurrent = vp.PInt64()
234		case "present":
235			ps.Present = vp.PInt64()
236		case "scope":
237			ps.Scope = value
238		case "serial_number":
239			ps.SerialNumber = value
240		case "status":
241			ps.Status = value
242		case "technology":
243			ps.Technology = value
244		case "temp":
245			ps.Temp = vp.PInt64()
246		case "temp_alert_max":
247			ps.TempAlertMax = vp.PInt64()
248		case "temp_alert_min":
249			ps.TempAlertMin = vp.PInt64()
250		case "temp_ambient":
251			ps.TempAmbient = vp.PInt64()
252		case "temp_ambient_max":
253			ps.TempAmbientMax = vp.PInt64()
254		case "temp_ambient_min":
255			ps.TempAmbientMin = vp.PInt64()
256		case "temp_max":
257			ps.TempMax = vp.PInt64()
258		case "temp_min":
259			ps.TempMin = vp.PInt64()
260		case "time_to_empty_avg":
261			ps.TimeToEmptyAvg = vp.PInt64()
262		case "time_to_empty_now":
263			ps.TimeToEmptyNow = vp.PInt64()
264		case "time_to_full_avg":
265			ps.TimeToFullAvg = vp.PInt64()
266		case "time_to_full_now":
267			ps.TimeToFullNow = vp.PInt64()
268		case "type":
269			ps.Type = value
270		case "usb_type":
271			ps.UsbType = value
272		case "voltage_avg":
273			ps.VoltageAvg = vp.PInt64()
274		case "voltage_boot":
275			ps.VoltageBoot = vp.PInt64()
276		case "voltage_max":
277			ps.VoltageMax = vp.PInt64()
278		case "voltage_max_design":
279			ps.VoltageMaxDesign = vp.PInt64()
280		case "voltage_min":
281			ps.VoltageMin = vp.PInt64()
282		case "voltage_min_design":
283			ps.VoltageMinDesign = vp.PInt64()
284		case "voltage_now":
285			ps.VoltageNow = vp.PInt64()
286		case "voltage_ocv":
287			ps.VoltageOCV = vp.PInt64()
288		}
289
290		if err := vp.Err(); err != nil {
291			return nil, err
292		}
293	}
294
295	return &ps, nil
296}
297