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