Really fix systat(1).
[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 <err.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "systat.h"
31 #include "extern.h"
32
33 struct sensor sensor;
34 struct sensordev sensordev;
35 int row, sensor_cnt;
36 void printline(void);
37 static char * fmttime(double);
38
39 WINDOW *
40 opensensors(void)
41 {
42         return (subwin(stdscr, LINES-5-1, 0, 5, 0));
43 }
44
45 void
46 closesensors(WINDOW *w)
47 {
48         if (w == NULL)
49                 return;
50         wclear(w);
51         wrefresh(w);
52         delwin(w);
53 }
54
55 void
56 labelsensors(void)
57 {
58         wmove(wnd, 0, 0);
59         wclrtobot(wnd);
60         mvwaddstr(wnd, 0, 0, "Sensor");
61         mvwaddstr(wnd, 0, 34, "Value");
62         mvwaddstr(wnd, 0, 45, "Status");
63         mvwaddstr(wnd, 0, 58, "Description");
64 }
65
66 void
67 fetchsensors(void)
68 {
69         enum sensor_type type;
70         size_t           slen, sdlen;
71         int              mib[5], dev, numt;
72
73         mib[0] = CTL_HW;
74         mib[1] = HW_SENSORS;
75         slen = sizeof(struct sensor);
76         sdlen = sizeof(struct sensordev);
77
78         row = 1;
79         sensor_cnt = 0;
80
81         wmove(wnd, row, 0);
82         wclrtobot(wnd);
83
84         for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
85                 mib[2] = dev;
86                 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
87                         if (errno != ENOENT)
88                                 warn("sysctl");
89                         continue;
90                 }
91                 for (type = 0; type < SENSOR_MAX_TYPES; type++) {
92                         mib[3] = type;
93                         for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
94                                 mib[4] = numt;
95                                 if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
96                                     == -1) {
97                                         if (errno != ENOENT)
98                                                 warn("sysctl");
99                                         continue;
100                                 }
101                                 if (sensor.flags & SENSOR_FINVALID)
102                                         continue;
103                                 sensor_cnt++;
104                                 printline();
105                         }
106                 }
107         }
108 }
109
110 const char *drvstat[] = {
111         NULL,
112         "empty", "ready", "powerup", "online", "idle", "active",
113         "rebuild", "powerdown", "fail", "pfail"
114 };
115
116 void
117 showsensors(void)
118 {
119         if (sensor_cnt == 0)
120                 mvwaddstr(wnd, row, 0, "No sensors found.");
121 }
122
123 int
124 initsensors(void)
125 {
126         return (1);
127 }
128
129 void
130 printline(void)
131 {
132         mvwprintw(wnd, row, 0, "%s.%s%d", sensordev.xname,
133             sensor_type_s[sensor.type], sensor.numt);
134         switch (sensor.type) {
135         case SENSOR_TEMP:
136                 mvwprintw(wnd, row, 24, "%10.2f degC",
137                     (sensor.value - 273150000) / 1000000.0);
138                 break;
139         case SENSOR_FANRPM:
140                 mvwprintw(wnd, row, 24, "%11lld RPM", sensor.value);
141                 break;
142         case SENSOR_VOLTS_DC:
143                 mvwprintw(wnd, row, 24, "%10.2f V DC",
144                     sensor.value / 1000000.0);
145                 break;
146         case SENSOR_AMPS:
147                 mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0);
148                 break;
149         case SENSOR_INDICATOR:
150                 mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off");
151                 break;
152         case SENSOR_INTEGER:
153                 mvwprintw(wnd, row, 24, "%11lld raw", sensor.value);
154                 break;
155         case SENSOR_PERCENT:
156                 mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0);
157                 break;
158         case SENSOR_LUX:
159                 mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0);
160                 break;
161         case SENSOR_DRIVE:
162                 if (0 < sensor.value &&
163                     (size_t)sensor.value < sizeof(drvstat)/sizeof(drvstat[0])) {
164                         mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]);
165                         break;
166                 }
167                 break;
168         case SENSOR_TIMEDELTA:
169                 mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0));
170                 break;
171         case SENSOR_WATTHOUR:
172                 mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0);
173                 break;
174         case SENSOR_AMPHOUR:
175                 mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0);
176                 break;
177         default:
178                 mvwprintw(wnd, row, 24, "%10lld", sensor.value);
179                 break;
180         }
181         if (sensor.desc[0] != '\0')
182                 mvwprintw(wnd, row, 58, "(%s)", sensor.desc);
183
184         switch (sensor.status) {
185         case SENSOR_S_UNSPEC:
186                 break;
187         case SENSOR_S_UNKNOWN:
188                 mvwaddstr(wnd, row, 45, "unknown");
189                 break;
190         case SENSOR_S_WARN:
191                 mvwaddstr(wnd, row, 45, "WARNING");
192                 break;
193         case SENSOR_S_CRIT:
194                 mvwaddstr(wnd, row, 45, "CRITICAL");
195                 break;
196         case SENSOR_S_OK:
197                 mvwaddstr(wnd, row, 45, "OK");
198                 break;
199         }
200         row++;
201 }
202
203 #define SECS_PER_DAY 86400
204 #define SECS_PER_HOUR 3600
205 #define SECS_PER_MIN 60
206
207 static char *
208 fmttime(double in)
209 {
210         int signbit = 1;
211         int tiny = 0;
212         const char *unit;
213 #define LEN 32
214         static char outbuf[LEN];
215
216         if (in < 0){
217                 signbit = -1;
218                 in *= -1;
219         }
220
221         if (in >= SECS_PER_DAY ){
222                 unit = "days";
223                 in /= SECS_PER_DAY;
224         } else if (in >= SECS_PER_HOUR ){
225                 unit = "hr";
226                 in /= SECS_PER_HOUR;
227         } else if (in >= SECS_PER_MIN ){
228                 unit = "min";
229                 in /= SECS_PER_MIN;
230         } else if (in >= 1 ){
231                 unit = "s";
232                 /* in *= 1; */ /* no op */
233         } else if (in == 0 ){ /* direct comparisons to floats are scary */
234                 unit = "s";
235         } else if (in >= 1e-3 ){
236                 unit = "ms";
237                 in *= 1e3;
238         } else if (in >= 1e-6 ){
239                 unit = "us";
240                 in *= 1e6;
241         } else if (in >= 1e-9 ){
242                 unit = "ns";
243                 in *= 1e9;
244         } else {
245                 unit = "ps";
246                 if (in < 1e-13)
247                         tiny = 1;
248                 in *= 1e12;
249         }
250
251         snprintf(outbuf, LEN, 
252             tiny ? "%s%lf %s" : "%s%.3lf %s", 
253             signbit == -1 ? "-" : "", in, unit);
254
255         return outbuf;
256 }