1 /* $OpenBSD: sensors.c,v 1.14 2008/12/07 02:56:06 canacar 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 char *devnames[MAXSENSORDEVICES]; 47 48 #define ADD_ALLOC 100 49 static size_t sensor_cnt = 0; 50 static size_t num_alloc = 0; 51 static struct sensinfo *sensors = NULL; 52 53 static char *fmttime(double); 54 static void showsensor(struct sensinfo *s); 55 56 void print_sn(void); 57 int read_sn(void); 58 int select_sn(void); 59 60 const char *drvstat[] = { 61 NULL, 62 "empty", "ready", "powerup", "online", "idle", "active", 63 "rebuild", "powerdown", "fail", "pfail" 64 }; 65 66 67 field_def fields_sn[] = { 68 {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 69 {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 70 {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0}, 71 {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} 72 }; 73 74 #define FIELD_ADDR(x) (&fields_sn[x]) 75 76 #define FLD_SN_SENSOR FIELD_ADDR(0) 77 #define FLD_SN_VALUE FIELD_ADDR(1) 78 #define FLD_SN_STATUS FIELD_ADDR(2) 79 #define FLD_SN_DESCR FIELD_ADDR(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 = realloc(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 < 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 error("sysctl: %s", strerror(errno)); 143 continue; 144 } 145 146 if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) { 147 free(devnames[dev]); 148 devnames[dev] = NULL; 149 } 150 if (devnames[dev] == NULL) 151 devnames[dev] = strdup(sensordev.xname); 152 153 for (type = 0; type < SENSOR_MAX_TYPES; type++) { 154 mib[3] = type; 155 for (numt = 0; numt < sensordev.maxnumt[type]; numt++) { 156 mib[4] = numt; 157 slen = sizeof(struct sensor); 158 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) 159 == -1) { 160 if (errno != ENOENT) 161 error("sysctl: %s", strerror(errno)); 162 continue; 163 } 164 if (sensor.flags & SENSOR_FINVALID) 165 continue; 166 167 s = next_sn(); 168 s->sn_sensor = sensor; 169 s->sn_dev = dev; 170 } 171 } 172 } 173 174 num_disp = sensor_cnt; 175 return 0; 176 } 177 178 179 void 180 print_sn(void) 181 { 182 int n, count = 0; 183 184 for (n = dispstart; n < num_disp; n++) { 185 showsensor(sensors + n); 186 count++; 187 if (maxprint > 0 && count >= maxprint) 188 break; 189 } 190 } 191 192 int 193 initsensors(void) 194 { 195 field_view *v; 196 197 memset(devnames, 0, sizeof(devnames)); 198 199 for (v = views_sn; v->name != NULL; v++) 200 add_view(v); 201 202 return(1); 203 } 204 205 static void 206 showsensor(struct sensinfo *s) 207 { 208 tb_start(); 209 tbprintf("%s.%s%d", devnames[s->sn_dev], 210 sensor_type_s[s->sn_type], s->sn_numt); 211 print_fld_tb(FLD_SN_SENSOR); 212 213 if (s->sn_desc[0] != '\0') 214 print_fld_str(FLD_SN_DESCR, s->sn_desc); 215 216 tb_start(); 217 218 switch (s->sn_type) { 219 case SENSOR_TEMP: 220 tbprintf("%10.2f degC", 221 (s->sn_value - 273150000) / 1000000.0); 222 break; 223 case SENSOR_FANRPM: 224 tbprintf("%11lld RPM", s->sn_value); 225 break; 226 case SENSOR_VOLTS_DC: 227 tbprintf("%10.2f V DC", 228 s->sn_value / 1000000.0); 229 break; 230 case SENSOR_AMPS: 231 tbprintf("%10.2f A", s->sn_value / 1000000.0); 232 break; 233 case SENSOR_INDICATOR: 234 tbprintf("%15s", s->sn_value ? "On" : "Off"); 235 break; 236 case SENSOR_INTEGER: 237 tbprintf("%11lld raw", s->sn_value); 238 break; 239 case SENSOR_PERCENT: 240 tbprintf("%14.2f%%", s->sn_value / 1000.0); 241 break; 242 case SENSOR_LUX: 243 tbprintf("%15.2f lx", s->sn_value / 1000000.0); 244 break; 245 case SENSOR_DRIVE: 246 if (0 < s->sn_value && 247 s->sn_value < sizeof(drvstat)/sizeof(drvstat[0])) { 248 tbprintf("%15s", drvstat[s->sn_value]); 249 break; 250 } 251 break; 252 case SENSOR_TIMEDELTA: 253 tbprintf("%15s", fmttime(s->sn_value / 1000000000.0)); 254 break; 255 case SENSOR_WATTHOUR: 256 tbprintf("%12.2f Wh", s->sn_value / 1000000.0); 257 break; 258 case SENSOR_AMPHOUR: 259 tbprintf("%10.2f Ah", s->sn_value / 1000000.0); 260 break; 261 default: 262 tbprintf("%10lld", s->sn_value); 263 break; 264 } 265 266 print_fld_tb(FLD_SN_VALUE); 267 268 switch (s->sn_status) { 269 case SENSOR_S_UNSPEC: 270 break; 271 case SENSOR_S_UNKNOWN: 272 print_fld_str(FLD_SN_STATUS, "unknown"); 273 break; 274 case SENSOR_S_WARN: 275 print_fld_str(FLD_SN_STATUS, "WARNING"); 276 break; 277 case SENSOR_S_CRIT: 278 print_fld_str(FLD_SN_STATUS, "CRITICAL"); 279 break; 280 case SENSOR_S_OK: 281 print_fld_str(FLD_SN_STATUS, "OK"); 282 break; 283 } 284 end_line(); 285 } 286 287 #define SECS_PER_DAY 86400 288 #define SECS_PER_HOUR 3600 289 #define SECS_PER_MIN 60 290 291 static char * 292 fmttime(double in) 293 { 294 int signbit = 1; 295 int tiny = 0; 296 char *unit; 297 #define LEN 32 298 static char outbuf[LEN]; 299 300 if (in < 0){ 301 signbit = -1; 302 in *= -1; 303 } 304 305 if (in >= SECS_PER_DAY ){ 306 unit = "days"; 307 in /= SECS_PER_DAY; 308 } else if (in >= SECS_PER_HOUR ){ 309 unit = "hr"; 310 in /= SECS_PER_HOUR; 311 } else if (in >= SECS_PER_MIN ){ 312 unit = "min"; 313 in /= SECS_PER_MIN; 314 } else if (in >= 1 ){ 315 unit = "s"; 316 /* in *= 1; */ /* no op */ 317 } else if (in == 0 ){ /* direct comparisons to floats are scary */ 318 unit = "s"; 319 } else if (in >= 1e-3 ){ 320 unit = "ms"; 321 in *= 1e3; 322 } else if (in >= 1e-6 ){ 323 unit = "us"; 324 in *= 1e6; 325 } else if (in >= 1e-9 ){ 326 unit = "ns"; 327 in *= 1e9; 328 } else { 329 unit = "ps"; 330 if (in < 1e-13) 331 tiny = 1; 332 in *= 1e12; 333 } 334 335 snprintf(outbuf, LEN, 336 tiny ? "%s%f %s" : "%s%.3f %s", 337 signbit == -1 ? "-" : "", in, unit); 338 339 return outbuf; 340 } 341