kernel - VM rework part 2 - Replace backing_object with backing_ba
[dragonfly.git] / usr.bin / systat / sensors.c
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_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 *
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
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 }