1 /* $OpenBSD: sensors.c,v 1.21 2010/04/20 20:49:35 deraadt 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 22 #include <sys/param.h> 23 #include <sys/sysctl.h> 24 #include <sys/sensors.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include "systat.h" 32 33 struct sensor sensor; 34 struct sensordev sensordev; 35 36 struct sensinfo { 37 int sn_dev; 38 struct sensor sn_sensor; 39 }; 40 #define sn_type sn_sensor.type 41 #define sn_numt sn_sensor.numt 42 #define sn_desc sn_sensor.desc 43 #define sn_status sn_sensor.status 44 #define sn_value sn_sensor.value 45 46 #define SYSTAT_MAXSENSORDEVICES 1024 47 char *devnames[SYSTAT_MAXSENSORDEVICES]; 48 49 #define ADD_ALLOC 100 50 static size_t sensor_cnt = 0; 51 static size_t num_alloc = 0; 52 static struct sensinfo *sensors = NULL; 53 54 static char *fmttime(double); 55 static void showsensor(struct sensinfo *s); 56 57 void print_sn(void); 58 int read_sn(void); 59 int select_sn(void); 60 61 const char *drvstat[] = { 62 NULL, 63 "empty", "ready", "powering up", "online", "idle", "active", 64 "rebuilding", "powering down", "failed", "degraded" 65 }; 66 67 68 field_def fields_sn[] = { 69 {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 70 {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 71 {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0}, 72 {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} 73 }; 74 75 #define FIELD_ADDR(x) (&fields_sn[x]) 76 77 #define FLD_SN_SENSOR FIELD_ADDR(0) 78 #define FLD_SN_VALUE FIELD_ADDR(1) 79 #define FLD_SN_STATUS FIELD_ADDR(2) 80 #define FLD_SN_DESCR FIELD_ADDR(3) 81 82 /* Define views */ 83 field_def *view_sn_0[] = { 84 FLD_SN_SENSOR, FLD_SN_VALUE, FLD_SN_STATUS, FLD_SN_DESCR, NULL 85 }; 86 87 88 /* Define view managers */ 89 struct view_manager sensors_mgr = { 90 "Sensors", select_sn, read_sn, NULL, print_header, 91 print_sn, keyboard_callback, NULL, NULL 92 }; 93 94 field_view views_sn[] = { 95 {view_sn_0, "sensors", '3', &sensors_mgr}, 96 {NULL, NULL, 0, NULL} 97 }; 98 99 struct sensinfo * 100 next_sn(void) 101 { 102 if (num_alloc <= sensor_cnt) { 103 struct sensinfo *s; 104 size_t a = num_alloc + ADD_ALLOC; 105 if (a < num_alloc) 106 return NULL; 107 s = realloc(sensors, a * sizeof(struct sensinfo)); 108 if (s == NULL) 109 return NULL; 110 sensors = s; 111 num_alloc = a; 112 } 113 114 return &sensors[sensor_cnt++]; 115 } 116 117 118 int 119 select_sn(void) 120 { 121 num_disp = sensor_cnt; 122 return (0); 123 } 124 125 int 126 read_sn(void) 127 { 128 enum sensor_type type; 129 size_t slen, sdlen; 130 int mib[5], dev, numt; 131 struct sensinfo *s; 132 133 mib[0] = CTL_HW; 134 mib[1] = HW_SENSORS; 135 136 sensor_cnt = 0; 137 138 for (dev = 0; dev < SYSTAT_MAXSENSORDEVICES; dev++) { 139 mib[2] = dev; 140 sdlen = sizeof(struct sensordev); 141 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 142 if (errno == ENOENT) 143 break; 144 if (errno == ENXIO) 145 continue; 146 error("sysctl: %s", strerror(errno)); 147 } 148 149 if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) { 150 free(devnames[dev]); 151 devnames[dev] = NULL; 152 } 153 if (devnames[dev] == NULL) 154 devnames[dev] = strdup(sensordev.xname); 155 156 for (type = 0; type < SENSOR_MAX_TYPES; type++) { 157 mib[3] = type; 158 for (numt = 0; numt < sensordev.maxnumt[type]; numt++) { 159 mib[4] = numt; 160 slen = sizeof(struct sensor); 161 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) 162 == -1) { 163 if (errno != ENOENT) 164 error("sysctl: %s", strerror(errno)); 165 continue; 166 } 167 if (sensor.flags & SENSOR_FINVALID) 168 continue; 169 170 s = next_sn(); 171 s->sn_sensor = sensor; 172 s->sn_dev = dev; 173 } 174 } 175 } 176 177 num_disp = sensor_cnt; 178 return 0; 179 } 180 181 182 void 183 print_sn(void) 184 { 185 int n, count = 0; 186 187 for (n = dispstart; n < num_disp; n++) { 188 showsensor(sensors + n); 189 count++; 190 if (maxprint > 0 && count >= maxprint) 191 break; 192 } 193 } 194 195 int 196 initsensors(void) 197 { 198 field_view *v; 199 200 memset(devnames, 0, sizeof(devnames)); 201 202 for (v = views_sn; v->name != NULL; v++) 203 add_view(v); 204 205 return(1); 206 } 207 208 static void 209 showsensor(struct sensinfo *s) 210 { 211 tb_start(); 212 tbprintf("%s.%s%d", devnames[s->sn_dev], 213 sensor_type_s[s->sn_type], s->sn_numt); 214 print_fld_tb(FLD_SN_SENSOR); 215 216 if (s->sn_desc[0] != '\0') 217 print_fld_str(FLD_SN_DESCR, s->sn_desc); 218 219 tb_start(); 220 221 switch (s->sn_type) { 222 case SENSOR_TEMP: 223 tbprintf("%10.2f degC", 224 (s->sn_value - 273150000) / 1000000.0); 225 break; 226 case SENSOR_FANRPM: 227 tbprintf("%11lld RPM", s->sn_value); 228 break; 229 case SENSOR_VOLTS_DC: 230 tbprintf("%10.2f V DC", 231 s->sn_value / 1000000.0); 232 break; 233 case SENSOR_WATTS: 234 tbprintf("%10.2f W", s->sn_value / 1000000.0); 235 break; 236 case SENSOR_AMPS: 237 tbprintf("%10.2f A", s->sn_value / 1000000.0); 238 break; 239 case SENSOR_INDICATOR: 240 tbprintf("%15s", s->sn_value ? "On" : "Off"); 241 break; 242 case SENSOR_INTEGER: 243 tbprintf("%11lld raw", s->sn_value); 244 break; 245 case SENSOR_PERCENT: 246 tbprintf("%14.2f%%", s->sn_value / 1000.0); 247 break; 248 case SENSOR_LUX: 249 tbprintf("%15.2f lx", s->sn_value / 1000000.0); 250 break; 251 case SENSOR_DRIVE: 252 if (0 < s->sn_value && 253 s->sn_value < sizeof(drvstat)/sizeof(drvstat[0])) { 254 tbprintf("%15s", drvstat[s->sn_value]); 255 break; 256 } 257 break; 258 case SENSOR_TIMEDELTA: 259 tbprintf("%15s", fmttime(s->sn_value / 1000000000.0)); 260 break; 261 case SENSOR_WATTHOUR: 262 tbprintf("%12.2f Wh", s->sn_value / 1000000.0); 263 break; 264 case SENSOR_AMPHOUR: 265 tbprintf("%10.2f Ah", s->sn_value / 1000000.0); 266 break; 267 case SENSOR_HUMIDITY: 268 tbprintf("%3.2f%%", s->sn_value / 1000.0); 269 break; 270 case SENSOR_FREQ: 271 tbprintf("%11lld Hz", s->sn_value); 272 break; 273 default: 274 tbprintf("%10lld", s->sn_value); 275 break; 276 } 277 278 print_fld_tb(FLD_SN_VALUE); 279 280 switch (s->sn_status) { 281 case SENSOR_S_UNSPEC: 282 break; 283 case SENSOR_S_UNKNOWN: 284 print_fld_str(FLD_SN_STATUS, "unknown"); 285 break; 286 case SENSOR_S_WARN: 287 print_fld_str(FLD_SN_STATUS, "WARNING"); 288 break; 289 case SENSOR_S_CRIT: 290 print_fld_str(FLD_SN_STATUS, "CRITICAL"); 291 break; 292 case SENSOR_S_OK: 293 print_fld_str(FLD_SN_STATUS, "OK"); 294 break; 295 } 296 end_line(); 297 } 298 299 #define SECS_PER_DAY 86400 300 #define SECS_PER_HOUR 3600 301 #define SECS_PER_MIN 60 302 303 static char * 304 fmttime(double in) 305 { 306 int signbit = 1; 307 int tiny = 0; 308 char *unit; 309 #define LEN 32 310 static char outbuf[LEN]; 311 312 if (in < 0){ 313 signbit = -1; 314 in *= -1; 315 } 316 317 if (in >= SECS_PER_DAY ){ 318 unit = "days"; 319 in /= SECS_PER_DAY; 320 } else if (in >= SECS_PER_HOUR ){ 321 unit = "hr"; 322 in /= SECS_PER_HOUR; 323 } else if (in >= SECS_PER_MIN ){ 324 unit = "min"; 325 in /= SECS_PER_MIN; 326 } else if (in >= 1 ){ 327 unit = "s"; 328 /* in *= 1; */ /* no op */ 329 } else if (in == 0 ){ /* direct comparisons to floats are scary */ 330 unit = "s"; 331 } else if (in >= 1e-3 ){ 332 unit = "ms"; 333 in *= 1e3; 334 } else if (in >= 1e-6 ){ 335 unit = "us"; 336 in *= 1e6; 337 } else if (in >= 1e-9 ){ 338 unit = "ns"; 339 in *= 1e9; 340 } else { 341 unit = "ps"; 342 if (in < 1e-13) 343 tiny = 1; 344 in *= 1e12; 345 } 346 347 snprintf(outbuf, LEN, 348 tiny ? "%s%f %s" : "%s%.3f %s", 349 signbit == -1 ? "-" : "", in, unit); 350 351 return outbuf; 352 } 353