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