/* $OpenBSD: sensors.c,v 1.33 2024/11/08 08:45:47 matthieu Exp $ */ /* * Copyright (c) 2007 Deanna Phillips * Copyright (c) 2003 Henning Brauer * Copyright (c) 2006 Constantine A. Murenin * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include #include #include #include #include #include #include #include #include #include #include "systat.h" struct sensor sensor; struct sensordev sensordev; struct sensinfo { int sn_dev; struct sensor sn_sensor; }; #define sn_type sn_sensor.type #define sn_numt sn_sensor.numt #define sn_desc sn_sensor.desc #define sn_status sn_sensor.status #define sn_value sn_sensor.value #define SYSTAT_MAXSENSORDEVICES 1024 char *devnames[SYSTAT_MAXSENSORDEVICES]; #define ADD_ALLOC 100 static size_t sensor_cnt = 0; static size_t num_alloc = 0; static struct sensinfo *sensors = NULL; static char *fmttime(double); static void showsensor(struct sensinfo *s); void print_sn(void); int read_sn(void); int select_sn(void); const char *drvstat[] = { NULL, "empty", "ready", "powering up", "online", "idle", "active", "rebuilding", "powering down", "failed", "degraded" }; field_def fields_sn[] = { {"SENSOR", 16, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, {"VALUE", 16, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, {"STATUS", 5, 8, 1, FLD_ALIGN_CENTER, -1, 0, 0, 0}, {"DESCRIPTION", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0} }; #define FLD_SN_SENSOR FIELD_ADDR(fields_sn,0) #define FLD_SN_VALUE FIELD_ADDR(fields_sn,1) #define FLD_SN_STATUS FIELD_ADDR(fields_sn,2) #define FLD_SN_DESCR FIELD_ADDR(fields_sn,3) /* Define views */ field_def *view_sn_0[] = { FLD_SN_SENSOR, FLD_SN_VALUE, FLD_SN_STATUS, FLD_SN_DESCR, NULL }; /* Define view managers */ struct view_manager sensors_mgr = { "Sensors", select_sn, read_sn, NULL, print_header, print_sn, keyboard_callback, NULL, NULL }; field_view views_sn[] = { {view_sn_0, "sensors", '3', &sensors_mgr}, {NULL, NULL, 0, NULL} }; struct sensinfo * next_sn(void) { if (num_alloc <= sensor_cnt) { struct sensinfo *s; size_t a = num_alloc + ADD_ALLOC; if (a < num_alloc) return NULL; s = reallocarray(sensors, a, sizeof(struct sensinfo)); if (s == NULL) return NULL; sensors = s; num_alloc = a; } return &sensors[sensor_cnt++]; } int select_sn(void) { num_disp = sensor_cnt; return (0); } int read_sn(void) { enum sensor_type type; size_t slen, sdlen; int mib[5], dev, numt; struct sensinfo *s; mib[0] = CTL_HW; mib[1] = HW_SENSORS; sensor_cnt = 0; for (dev = 0; dev < SYSTAT_MAXSENSORDEVICES; dev++) { mib[2] = dev; sdlen = sizeof(struct sensordev); if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { if (errno == ENOENT) break; if (errno == ENXIO) continue; error("sysctl: %s", strerror(errno)); } if (devnames[dev] && strcmp(devnames[dev], sensordev.xname)) { free(devnames[dev]); devnames[dev] = NULL; } if (devnames[dev] == NULL) devnames[dev] = strdup(sensordev.xname); for (type = 0; type < SENSOR_MAX_TYPES; type++) { mib[3] = type; for (numt = 0; numt < sensordev.maxnumt[type]; numt++) { mib[4] = numt; slen = sizeof(struct sensor); if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { if (errno != ENOENT) error("sysctl: %s", strerror(errno)); continue; } if (sensor.flags & SENSOR_FINVALID) continue; s = next_sn(); s->sn_sensor = sensor; s->sn_dev = dev; } } } num_disp = sensor_cnt; return 0; } void print_sn(void) { int n, count = 0; for (n = dispstart; n < num_disp; n++) { showsensor(sensors + n); count++; if (maxprint > 0 && count >= maxprint) break; } } int initsensors(void) { field_view *v; memset(devnames, 0, sizeof(devnames)); for (v = views_sn; v->name != NULL; v++) add_view(v); return(1); } static void showsensor(struct sensinfo *s) { tb_start(); tbprintf("%s.%s%d", devnames[s->sn_dev], sensor_type_s[s->sn_type], s->sn_numt); print_fld_tb(FLD_SN_SENSOR); if (s->sn_desc[0] != '\0') print_fld_str(FLD_SN_DESCR, s->sn_desc); tb_start(); switch (s->sn_type) { case SENSOR_TEMP: tbprintf("%10.2f degC", (s->sn_value - 273150000) / 1000000.0); break; case SENSOR_FANRPM: tbprintf("%11lld RPM", s->sn_value); break; case SENSOR_VOLTS_DC: tbprintf("%10.2f V DC", s->sn_value / 1000000.0); break; case SENSOR_VOLTS_AC: tbprintf("%10.2f V AC", s->sn_value / 1000000.0); break; case SENSOR_OHMS: tbprintf("%11lld ohm", s->sn_value); break; case SENSOR_WATTS: tbprintf("%10.2f W", s->sn_value / 1000000.0); break; case SENSOR_AMPS: tbprintf("%10.2f A", s->sn_value / 1000000.0); break; case SENSOR_WATTHOUR: tbprintf("%12.2f Wh", s->sn_value / 1000000.0); break; case SENSOR_AMPHOUR: tbprintf("%10.2f Ah", s->sn_value / 1000000.0); break; case SENSOR_INDICATOR: tbprintf("%15s", s->sn_value ? "On" : "Off"); break; case SENSOR_INTEGER: tbprintf("%11lld raw", s->sn_value); break; case SENSOR_PERCENT: tbprintf("%14.2f%%", s->sn_value / 1000.0); break; case SENSOR_LUX: tbprintf("%15.2f lx", s->sn_value / 1000000.0); break; case SENSOR_DRIVE: if (0 < s->sn_value && s->sn_value < sizeof(drvstat)/sizeof(drvstat[0])) { tbprintf("%15s", drvstat[s->sn_value]); break; } break; case SENSOR_TIMEDELTA: tbprintf("%15s", fmttime(s->sn_value / 1000000000.0)); break; case SENSOR_HUMIDITY: tbprintf("%3.2f%%", s->sn_value / 1000.0); break; case SENSOR_FREQ: if (humanreadable) { char buf[FMT_SCALED_STRSIZE]; fmt_scaled(s->sn_value / 1000000.0, buf); tbprintf("%sHz", buf); } else tbprintf("%11.2f Hz", s->sn_value / 1000000.0); break; case SENSOR_ANGLE: tbprintf("%3.4f degrees", s->sn_value / 1000000.0); break; case SENSOR_DISTANCE: tbprintf("%.3f m", s->sn_value / 1000000.0); break; case SENSOR_PRESSURE: tbprintf("%.2f Pa", s->sn_value / 1000.0); break; case SENSOR_ACCEL: tbprintf("%2.4f m/s^2", s->sn_value / 1000000.0); break; case SENSOR_VELOCITY: tbprintf("%4.3f m/s", s->sn_value / 1000000.0); break; case SENSOR_ENERGY: tbprintf("%.2f J", s->sn_value / 1000000.0); break; default: tbprintf("%10lld", s->sn_value); break; } print_fld_tb(FLD_SN_VALUE); switch (s->sn_status) { case SENSOR_S_UNSPEC: break; case SENSOR_S_UNKNOWN: print_fld_str(FLD_SN_STATUS, "unknown"); break; case SENSOR_S_WARN: print_fld_str(FLD_SN_STATUS, "WARNING"); break; case SENSOR_S_CRIT: print_fld_str(FLD_SN_STATUS, "CRITICAL"); break; case SENSOR_S_OK: print_fld_str(FLD_SN_STATUS, "OK"); break; } end_line(); } #define SECS_PER_DAY 86400 #define SECS_PER_HOUR 3600 #define SECS_PER_MIN 60 static char * fmttime(double in) { int signbit = 1; int tiny = 0; char *unit; #define LEN 32 static char outbuf[LEN]; if (in < 0){ signbit = -1; in *= -1; } if (in >= SECS_PER_DAY ){ unit = "days"; in /= SECS_PER_DAY; } else if (in >= SECS_PER_HOUR ){ unit = "hr"; in /= SECS_PER_HOUR; } else if (in >= SECS_PER_MIN ){ unit = "min"; in /= SECS_PER_MIN; } else if (in >= 1 ){ unit = "s"; /* in *= 1; */ /* no op */ } else if (in == 0 ){ /* direct comparisons to floats are scary */ unit = "s"; } else if (in >= 1e-3 ){ unit = "ms"; in *= 1e3; } else if (in >= 1e-6 ){ unit = "us"; in *= 1e6; } else if (in >= 1e-9 ){ unit = "ns"; in *= 1e9; } else { unit = "ps"; if (in < 1e-13) tiny = 1; in *= 1e12; } snprintf(outbuf, LEN, tiny ? "%s%f %s" : "%s%.3f %s", signbit == -1 ? "-" : "", in, unit); return outbuf; }