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