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