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