xref: /dragonfly/usr.bin/systat/sensors.c (revision 745703c7)
1 /* $OpenBSD: sensors.c,v 1.11 2007/03/23 14:48:22 ckuethe Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Deanna Phillips <deanna@openbsd.org>
5  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
6  * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/param.h>
22 #include <sys/sysctl.h>
23 #include <sys/sensors.h>
24 
25 #include <ctype.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "systat.h"
33 #include "extern.h"
34 
35 struct sensor sensor;
36 struct sensordev sensordev;
37 int row, sensor_cnt;
38 void printline(void);
39 static char * fmttime(double);
40 
41 struct sensordev_xname {
42 	char	xname[24];
43 	int	xname_len;
44 	u_int	flags;	/* XNAME_FLAG_ */
45 };
46 
47 #define XNAME_FLAG_WILDCARD	0x1
48 
49 static int	sensors_enabled[SENSOR_MAX_TYPES];
50 
51 #define XNAME_MAX		64
52 
53 static int	sensordev_xname_cnt;
54 static struct sensordev_xname sensordev_xname[XNAME_MAX];
55 
56 WINDOW *
57 opensensors(void)
58 {
59 	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
60 }
61 
62 void
63 closesensors(WINDOW *w)
64 {
65 	if (w == NULL)
66 		return;
67 	wclear(w);
68 	wrefresh(w);
69 	delwin(w);
70 }
71 
72 void
73 labelsensors(void)
74 {
75 	wmove(wnd, 0, 0);
76 	wclrtobot(wnd);
77 	mvwaddstr(wnd, 0, 0, "Sensor");
78 	mvwaddstr(wnd, 0, 34, "Value");
79 	mvwaddstr(wnd, 0, 45, "Status");
80 	mvwaddstr(wnd, 0, 58, "Description");
81 }
82 
83 void
84 fetchsensors(void)
85 {
86 	enum sensor_type type;
87 	size_t		 slen, sdlen, idmax_len;
88 	int		 mib[5], dev, numt, idmax;
89 	int		 maxsensordevices;
90 
91 	maxsensordevices = MAXSENSORDEVICES;
92 	idmax_len = sizeof(idmax);
93 	if (sysctlbyname("hw.sensors.dev_idmax", &idmax, &idmax_len,
94 	    NULL, 0) == 0)
95 		maxsensordevices = idmax;
96 
97 	mib[0] = CTL_HW;
98 	mib[1] = HW_SENSORS;
99 	slen = sizeof(struct sensor);
100 	sdlen = sizeof(struct sensordev);
101 
102 	row = 1;
103 	sensor_cnt = 0;
104 
105 	wmove(wnd, row, 0);
106 	wclrtobot(wnd);
107 
108 	for (dev = 0; dev < maxsensordevices; dev++) {
109 		mib[2] = dev;
110 		if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
111 			if (errno != ENOENT)
112 				warn("sysctl");
113 			continue;
114 		}
115 
116 		if (sensordev_xname_cnt > 0) {
117 			int i, match = 0, xname_len;
118 
119 			xname_len = strlen(sensordev.xname);
120 			for (i = 0; i < sensordev_xname_cnt; ++i) {
121 				const struct sensordev_xname *x;
122 
123 				x = &sensordev_xname[i];
124 				if (x->flags & XNAME_FLAG_WILDCARD) {
125 					if (xname_len <= x->xname_len)
126 						continue;
127 					if (!isdigit(
128 					    sensordev.xname[x->xname_len]))
129 						continue;
130 					if (strncmp(x->xname, sensordev.xname,
131 					    x->xname_len) == 0) {
132 						match = 1;
133 						break;
134 					}
135 				} else if (xname_len == x->xname_len &&
136 				    strcmp(x->xname, sensordev.xname) == 0) {
137 					match = 1;
138 					break;
139 				}
140 			}
141 			if (!match)
142 				continue;
143 		}
144 
145 		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
146 			if (!sensors_enabled[type])
147 				continue;
148 
149 			mib[3] = type;
150 			for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
151 				mib[4] = numt;
152 				if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
153 				    == -1) {
154 					if (errno != ENOENT)
155 						warn("sysctl");
156 					continue;
157 				}
158 				if (sensor.flags & SENSOR_FINVALID)
159 					continue;
160 				sensor_cnt++;
161 				printline();
162 			}
163 		}
164 	}
165 }
166 
167 const char *drvstat[] = {
168 	NULL,
169 	"empty", "ready", "powerup", "online", "idle", "active",
170 	"rebuild", "powerdown", "fail", "pfail"
171 };
172 
173 void
174 showsensors(void)
175 {
176 	if (sensor_cnt == 0)
177 		mvwaddstr(wnd, row, 0, "No sensors found.");
178 }
179 
180 int
181 initsensors(void)
182 {
183 	int i;
184 
185 	for (i = 0; i < SENSOR_MAX_TYPES; ++i)
186 		sensors_enabled[i] = 1;
187 	return (1);
188 }
189 
190 void
191 printline(void)
192 {
193 	mvwprintw(wnd, row, 0, "%s.%s%d", sensordev.xname,
194 	    sensor_type_s[sensor.type], sensor.numt);
195 	switch (sensor.type) {
196 	case SENSOR_TEMP:
197 		mvwprintw(wnd, row, 24, "%10.2f degC",
198 		    (sensor.value - 273150000) / 1000000.0);
199 		break;
200 	case SENSOR_FANRPM:
201 		mvwprintw(wnd, row, 24, "%11lld RPM", sensor.value);
202 		break;
203 	case SENSOR_VOLTS_DC:
204 		mvwprintw(wnd, row, 24, "%10.2f V DC",
205 		    sensor.value / 1000000.0);
206 		break;
207 	case SENSOR_AMPS:
208 		mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0);
209 		break;
210 	case SENSOR_INDICATOR:
211 		mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off");
212 		break;
213 	case SENSOR_INTEGER:
214 		mvwprintw(wnd, row, 24, "%11lld raw", sensor.value);
215 		break;
216 	case SENSOR_PERCENT:
217 		mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0);
218 		break;
219 	case SENSOR_LUX:
220 		mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0);
221 		break;
222 	case SENSOR_DRIVE:
223 		if (0 < sensor.value &&
224 		    (size_t)sensor.value < sizeof(drvstat)/sizeof(drvstat[0])) {
225 			mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]);
226 			break;
227 		}
228 		break;
229 	case SENSOR_TIMEDELTA:
230 		mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0));
231 		break;
232 	case SENSOR_WATTHOUR:
233 		mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0);
234 		break;
235 	case SENSOR_AMPHOUR:
236 		mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0);
237 		break;
238 	default:
239 		mvwprintw(wnd, row, 24, "%10lld", sensor.value);
240 		break;
241 	}
242 	if (sensor.desc[0] != '\0')
243 		mvwprintw(wnd, row, 58, "(%s)", sensor.desc);
244 
245 	switch (sensor.status) {
246 	case SENSOR_S_UNSPEC:
247 		break;
248 	case SENSOR_S_UNKNOWN:
249 		mvwaddstr(wnd, row, 45, "unknown");
250 		break;
251 	case SENSOR_S_WARN:
252 		mvwaddstr(wnd, row, 45, "WARNING");
253 		break;
254 	case SENSOR_S_CRIT:
255 		mvwaddstr(wnd, row, 45, "CRITICAL");
256 		break;
257 	case SENSOR_S_OK:
258 		mvwaddstr(wnd, row, 45, "OK");
259 		break;
260 	}
261 	row++;
262 }
263 
264 #define SECS_PER_DAY 86400
265 #define SECS_PER_HOUR 3600
266 #define SECS_PER_MIN 60
267 
268 static char *
269 fmttime(double in)
270 {
271 	int signbit = 1;
272 	int tiny = 0;
273 	const char *unit;
274 #define LEN 32
275 	static char outbuf[LEN];
276 
277 	if (in < 0){
278 		signbit = -1;
279 		in *= -1;
280 	}
281 
282 	if (in >= SECS_PER_DAY ){
283 		unit = "days";
284 		in /= SECS_PER_DAY;
285 	} else if (in >= SECS_PER_HOUR ){
286 		unit = "hr";
287 		in /= SECS_PER_HOUR;
288 	} else if (in >= SECS_PER_MIN ){
289 		unit = "min";
290 		in /= SECS_PER_MIN;
291 	} else if (in >= 1 ){
292 		unit = "s";
293 		/* in *= 1; */ /* no op */
294 	} else if (in == 0 ){ /* direct comparisons to floats are scary */
295 		unit = "s";
296 	} else if (in >= 1e-3 ){
297 		unit = "ms";
298 		in *= 1e3;
299 	} else if (in >= 1e-6 ){
300 		unit = "us";
301 		in *= 1e6;
302 	} else if (in >= 1e-9 ){
303 		unit = "ns";
304 		in *= 1e9;
305 	} else {
306 		unit = "ps";
307 		if (in < 1e-13)
308 			tiny = 1;
309 		in *= 1e12;
310 	}
311 
312 	snprintf(outbuf, LEN,
313 	    tiny ? "%s%lf %s" : "%s%.3lf %s",
314 	    signbit == -1 ? "-" : "", in, unit);
315 
316 	return outbuf;
317 }
318 
319 int
320 cmdsensors(const char *cmd, char *args)
321 {
322 	if (prefix(cmd, "type")) {
323 		const char *t;
324 		int i, has_type = 0;
325 
326 		for (i = 0; i < SENSOR_MAX_TYPES; ++i)
327 			sensors_enabled[i] = 0;
328 
329 		while ((t = strsep(&args, " ")) != NULL) {
330 			if (*t == '\0')
331 				continue;
332 
333 			has_type = 1;
334 			for (i = 0; i < SENSOR_MAX_TYPES; ++i) {
335 				if (strcmp(t, sensor_type_s[i]) == 0) {
336 					sensors_enabled[i] = 1;
337 					break;
338 				}
339 			}
340 		}
341 
342 		if (!has_type) {
343 			for (i = 0; i < SENSOR_MAX_TYPES; ++i)
344 				sensors_enabled[i] = 1;
345 		}
346 	} else if (prefix(cmd, "match")) {
347 		const char *xname;
348 
349 		sensordev_xname_cnt = 0;
350 		while ((xname = strsep(&args, " ")) != NULL) {
351 			struct sensordev_xname *x;
352 			int xname_len, cp_len;
353 
354 			xname_len = strlen(xname);
355 			if (xname_len == 0)
356 				continue;
357 
358 			x = &sensordev_xname[sensordev_xname_cnt];
359 			x->flags = 0;
360 
361 			if (xname[xname_len - 1] == '*') {
362 				--xname_len;
363 				if (xname_len == 0)
364 					continue;
365 				x->flags |= XNAME_FLAG_WILDCARD;
366 			}
367 			cp_len = xname_len;
368 			if (cp_len >= (int)sizeof(x->xname))
369 				cp_len = sizeof(x->xname) - 1;
370 
371 			memcpy(x->xname, xname, cp_len);
372 			x->xname[cp_len] = '\0';
373 			x->xname_len = strlen(x->xname);
374 
375 			sensordev_xname_cnt++;
376 			if (sensordev_xname_cnt == XNAME_MAX)
377 				break;
378 		}
379 	}
380 
381 	wclear(wnd);
382 	labelsensors();
383 	refresh();
384 	return (1);
385 }
386