1 /* $OpenBSD: sensors.c,v 1.27 2012/09/20 20:11:58 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 case SENSOR_DISTANCE: 282 printf("%.2f mm", s->sn_value / 1000.0); 283 break; 284 case SENSOR_PRESSURE: 285 printf("%.2f Pa", s->sn_value / 1000.0); 286 break; 287 case SENSOR_ACCEL: 288 printf("%2.4f m/s^2", s->sn_value / 1000000.0); 289 break; 290 default: 291 tbprintf("%10lld", s->sn_value); 292 break; 293 } 294 295 print_fld_tb(FLD_SN_VALUE); 296 297 switch (s->sn_status) { 298 case SENSOR_S_UNSPEC: 299 break; 300 case SENSOR_S_UNKNOWN: 301 print_fld_str(FLD_SN_STATUS, "unknown"); 302 break; 303 case SENSOR_S_WARN: 304 print_fld_str(FLD_SN_STATUS, "WARNING"); 305 break; 306 case SENSOR_S_CRIT: 307 print_fld_str(FLD_SN_STATUS, "CRITICAL"); 308 break; 309 case SENSOR_S_OK: 310 print_fld_str(FLD_SN_STATUS, "OK"); 311 break; 312 } 313 end_line(); 314 } 315 316 #define SECS_PER_DAY 86400 317 #define SECS_PER_HOUR 3600 318 #define SECS_PER_MIN 60 319 320 static char * 321 fmttime(double in) 322 { 323 int signbit = 1; 324 int tiny = 0; 325 char *unit; 326 #define LEN 32 327 static char outbuf[LEN]; 328 329 if (in < 0){ 330 signbit = -1; 331 in *= -1; 332 } 333 334 if (in >= SECS_PER_DAY ){ 335 unit = "days"; 336 in /= SECS_PER_DAY; 337 } else if (in >= SECS_PER_HOUR ){ 338 unit = "hr"; 339 in /= SECS_PER_HOUR; 340 } else if (in >= SECS_PER_MIN ){ 341 unit = "min"; 342 in /= SECS_PER_MIN; 343 } else if (in >= 1 ){ 344 unit = "s"; 345 /* in *= 1; */ /* no op */ 346 } else if (in == 0 ){ /* direct comparisons to floats are scary */ 347 unit = "s"; 348 } else if (in >= 1e-3 ){ 349 unit = "ms"; 350 in *= 1e3; 351 } else if (in >= 1e-6 ){ 352 unit = "us"; 353 in *= 1e6; 354 } else if (in >= 1e-9 ){ 355 unit = "ns"; 356 in *= 1e9; 357 } else { 358 unit = "ps"; 359 if (in < 1e-13) 360 tiny = 1; 361 in *= 1e12; 362 } 363 364 snprintf(outbuf, LEN, 365 tiny ? "%s%f %s" : "%s%.3f %s", 366 signbit == -1 ? "-" : "", in, unit); 367 368 return outbuf; 369 } 370