xref: /dragonfly/usr.bin/systat/sensors.c (revision e62ef63cd8bf9a1124d7110b8e05ff70a95d58e1)
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 *
opensensors(void)58 opensensors(void)
59 {
60           return (subwin(stdscr, LINES-5-1, 0, 5, 0));
61 }
62 
63 void
closesensors(WINDOW * w)64 closesensors(WINDOW *w)
65 {
66           if (w == NULL)
67                     return;
68           wclear(w);
69           wrefresh(w);
70           delwin(w);
71 }
72 
73 void
labelsensors(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
fetchsensors(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
showsensors(void)175 showsensors(void)
176 {
177           if (sensor_cnt == 0)
178                     mvwaddstr(wnd, row, 0, "No sensors found.");
179 }
180 
181 int
initsensors(void)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
printline(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_WATTS:
211                     mvwprintw(wnd, row, 24, "%13.2f W", sensor.value / 1000000.0);
212                     break;
213           case SENSOR_AMPS:
214                     mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0);
215                     break;
216           case SENSOR_INDICATOR:
217                     mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off");
218                     break;
219           case SENSOR_INTEGER:
220                     mvwprintw(wnd, row, 24, "%11lld raw", sensor.value);
221                     break;
222           case SENSOR_PERCENT:
223                     mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0);
224                     break;
225           case SENSOR_LUX:
226                     mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0);
227                     break;
228           case SENSOR_DRIVE:
229                     if (0 < sensor.value &&
230                         (size_t)sensor.value < NELEM(drvstat)) {
231                               mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]);
232                               break;
233                     }
234                     break;
235           case SENSOR_TIMEDELTA:
236                     mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0));
237                     break;
238           case SENSOR_WATTHOUR:
239                     mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0);
240                     break;
241           case SENSOR_AMPHOUR:
242                     mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0);
243                     break;
244           case SENSOR_FREQ:
245                     humanize_number(buf, sizeof(buf), sensor.value, "Hz",
246                         HN_AUTOSCALE, HN_DIVISOR_1000 | HN_DECIMAL);
247                     mvwprintw(wnd, row, 24, "%15s", buf);
248                     break;
249           default:
250                     mvwprintw(wnd, row, 24, "%10lld", sensor.value);
251                     break;
252           }
253           if (sensor.desc[0] != '\0')
254                     mvwprintw(wnd, row, 58, "(%s)", sensor.desc);
255 
256           switch (sensor.status) {
257           case SENSOR_S_UNSPEC:
258                     break;
259           case SENSOR_S_UNKNOWN:
260                     mvwaddstr(wnd, row, 45, "unknown");
261                     break;
262           case SENSOR_S_WARN:
263                     mvwaddstr(wnd, row, 45, "WARNING");
264                     break;
265           case SENSOR_S_CRIT:
266                     mvwaddstr(wnd, row, 45, "CRITICAL");
267                     break;
268           case SENSOR_S_OK:
269                     mvwaddstr(wnd, row, 45, "OK");
270                     break;
271           }
272           row++;
273 }
274 
275 #define SECS_PER_DAY 86400
276 #define SECS_PER_HOUR 3600
277 #define SECS_PER_MIN 60
278 
279 static char *
fmttime(double in)280 fmttime(double in)
281 {
282           int signbit = 1;
283           int tiny = 0;
284           const char *unit;
285 #define LEN 32
286           static char outbuf[LEN];
287 
288           if (in < 0){
289                     signbit = -1;
290                     in *= -1;
291           }
292 
293           if (in >= SECS_PER_DAY ){
294                     unit = "days";
295                     in /= SECS_PER_DAY;
296           } else if (in >= SECS_PER_HOUR ){
297                     unit = "hr";
298                     in /= SECS_PER_HOUR;
299           } else if (in >= SECS_PER_MIN ){
300                     unit = "min";
301                     in /= SECS_PER_MIN;
302           } else if (in >= 1 ){
303                     unit = "s";
304                     /* in *= 1; */ /* no op */
305           } else if (in == 0 ){ /* direct comparisons to floats are scary */
306                     unit = "s";
307           } else if (in >= 1e-3 ){
308                     unit = "ms";
309                     in *= 1e3;
310           } else if (in >= 1e-6 ){
311                     unit = "us";
312                     in *= 1e6;
313           } else if (in >= 1e-9 ){
314                     unit = "ns";
315                     in *= 1e9;
316           } else {
317                     unit = "ps";
318                     if (in < 1e-13)
319                               tiny = 1;
320                     in *= 1e12;
321           }
322 
323           snprintf(outbuf, LEN,
324               tiny ? "%s%lf %s" : "%s%.3lf %s",
325               signbit == -1 ? "-" : "", in, unit);
326 
327           return outbuf;
328 }
329 
330 int
cmdsensors(const char * cmd,char * args)331 cmdsensors(const char *cmd, char *args)
332 {
333           if (prefix(cmd, "type")) {
334                     const char *t;
335                     int i, has_type = 0;
336 
337                     for (i = 0; i < SENSOR_MAX_TYPES; ++i)
338                               sensors_enabled[i] = 0;
339 
340                     while ((t = strsep(&args, " ")) != NULL) {
341                               if (*t == '\0')
342                                         continue;
343 
344                               has_type = 1;
345                               for (i = 0; i < SENSOR_MAX_TYPES; ++i) {
346                                         if (strcmp(t, sensor_type_s[i]) == 0) {
347                                                   sensors_enabled[i] = 1;
348                                                   break;
349                                         }
350                               }
351                     }
352 
353                     if (!has_type) {
354                               for (i = 0; i < SENSOR_MAX_TYPES; ++i)
355                                         sensors_enabled[i] = 1;
356                     }
357           } else if (prefix(cmd, "match")) {
358                     const char *xname;
359 
360                     sensordev_xname_cnt = 0;
361                     while ((xname = strsep(&args, " ")) != NULL) {
362                               struct sensordev_xname *x;
363                               int xname_len, cp_len;
364 
365                               xname_len = strlen(xname);
366                               if (xname_len == 0)
367                                         continue;
368 
369                               x = &sensordev_xname[sensordev_xname_cnt];
370                               x->flags = 0;
371 
372                               if (xname[xname_len - 1] == '*') {
373                                         --xname_len;
374                                         if (xname_len == 0)
375                                                   continue;
376                                         x->flags |= XNAME_FLAG_WILDCARD;
377                               }
378                               cp_len = xname_len;
379                               if (cp_len >= (int)sizeof(x->xname))
380                                         cp_len = sizeof(x->xname) - 1;
381 
382                               memcpy(x->xname, xname, cp_len);
383                               x->xname[cp_len] = '\0';
384                               x->xname_len = strlen(x->xname);
385 
386                               sensordev_xname_cnt++;
387                               if (sensordev_xname_cnt == XNAME_MAX)
388                                         break;
389                     }
390           }
391 
392           wclear(wnd);
393           labelsensors();
394           refresh();
395           return (1);
396 }
397