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 } 397