#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/sensors.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "systat.h"
#include "extern.h"
struct sensor sensor;
struct sensordev sensordev;
int row, sensor_cnt;
void printline(void);
static char * fmttime(double);
struct sensordev_xname {
char xname[24];
int xname_len;
u_int flags;
};
#define XNAME_FLAG_WILDCARD 0x1
static int sensors_enabled[SENSOR_MAX_TYPES];
#define XNAME_MAX 64
static int sensordev_xname_cnt;
static struct sensordev_xname sensordev_xname[XNAME_MAX];
WINDOW *
opensensors(void)
{
return (subwin(stdscr, LINES-5-1, 0, 5, 0));
}
void
closesensors(WINDOW *w)
{
if (w == NULL)
return;
wclear(w);
wrefresh(w);
delwin(w);
}
void
labelsensors(void)
{
wmove(wnd, 0, 0);
wclrtobot(wnd);
mvwaddstr(wnd, 0, 0, "Sensor");
mvwaddstr(wnd, 0, 34, "Value");
mvwaddstr(wnd, 0, 45, "Status");
mvwaddstr(wnd, 0, 58, "Description");
}
void
fetchsensors(void)
{
enum sensor_type type;
size_t slen, sdlen, idmax_len;
int mib[5], dev, numt, idmax;
int maxsensordevices;
maxsensordevices = MAXSENSORDEVICES;
idmax_len = sizeof(idmax);
if (sysctlbyname("hw.sensors.dev_idmax", &idmax, &idmax_len,
NULL, 0) == 0)
maxsensordevices = idmax;
mib[0] = CTL_HW;
mib[1] = HW_SENSORS;
slen = sizeof(struct sensor);
sdlen = sizeof(struct sensordev);
row = 1;
sensor_cnt = 0;
wmove(wnd, row, 0);
wclrtobot(wnd);
for (dev = 0; dev < maxsensordevices; dev++) {
mib[2] = dev;
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
if (errno != ENOENT)
warn("sysctl");
continue;
}
if (sensordev_xname_cnt > 0) {
int i, match = 0, xname_len;
xname_len = strlen(sensordev.xname);
for (i = 0; i < sensordev_xname_cnt; ++i) {
const struct sensordev_xname *x;
x = &sensordev_xname[i];
if (x->flags & XNAME_FLAG_WILDCARD) {
if (xname_len <= x->xname_len)
continue;
if (!isdigit(
sensordev.xname[x->xname_len]))
continue;
if (strncmp(x->xname, sensordev.xname,
x->xname_len) == 0) {
match = 1;
break;
}
} else if (xname_len == x->xname_len &&
strcmp(x->xname, sensordev.xname) == 0) {
match = 1;
break;
}
}
if (!match)
continue;
}
for (type = 0; type < SENSOR_MAX_TYPES; type++) {
if (!sensors_enabled[type])
continue;
mib[3] = type;
for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
mib[4] = numt;
if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
== -1) {
if (errno != ENOENT)
warn("sysctl");
continue;
}
if (sensor.flags & SENSOR_FINVALID)
continue;
sensor_cnt++;
printline();
}
}
}
}
const char *drvstat[] = {
NULL,
"empty", "ready", "powerup", "online", "idle", "active",
"rebuild", "powerdown", "fail", "pfail"
};
void
showsensors(void)
{
if (sensor_cnt == 0)
mvwaddstr(wnd, row, 0, "No sensors found.");
}
int
initsensors(void)
{
int i;
for (i = 0; i < SENSOR_MAX_TYPES; ++i)
sensors_enabled[i] = 1;
return (1);
}
void
printline(void)
{
char buf[9];
mvwprintw(wnd, row, 0, "%s.%s%d", sensordev.xname,
sensor_type_s[sensor.type], sensor.numt);
switch (sensor.type) {
case SENSOR_TEMP:
mvwprintw(wnd, row, 24, "%10.2f degC",
(sensor.value - 273150000) / 1000000.0);
break;
case SENSOR_FANRPM:
mvwprintw(wnd, row, 24, "%11lld RPM", sensor.value);
break;
case SENSOR_VOLTS_DC:
mvwprintw(wnd, row, 24, "%10.2f V DC",
sensor.value / 1000000.0);
break;
case SENSOR_WATTS:
mvwprintw(wnd, row, 24, "%13.2f W", sensor.value / 1000000.0);
break;
case SENSOR_AMPS:
mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0);
break;
case SENSOR_INDICATOR:
mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off");
break;
case SENSOR_INTEGER:
mvwprintw(wnd, row, 24, "%11lld raw", sensor.value);
break;
case SENSOR_PERCENT:
mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0);
break;
case SENSOR_LUX:
mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0);
break;
case SENSOR_DRIVE:
if (0 < sensor.value &&
(size_t)sensor.value < NELEM(drvstat)) {
mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]);
break;
}
break;
case SENSOR_TIMEDELTA:
mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0));
break;
case SENSOR_WATTHOUR:
mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0);
break;
case SENSOR_AMPHOUR:
mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0);
break;
case SENSOR_FREQ:
humanize_number(buf, sizeof(buf), sensor.value, "Hz",
HN_AUTOSCALE, HN_DIVISOR_1000 | HN_DECIMAL);
mvwprintw(wnd, row, 24, "%15s", buf);
break;
default:
mvwprintw(wnd, row, 24, "%10lld", sensor.value);
break;
}
if (sensor.desc[0] != '\0')
mvwprintw(wnd, row, 58, "(%s)", sensor.desc);
switch (sensor.status) {
case SENSOR_S_UNSPEC:
break;
case SENSOR_S_UNKNOWN:
mvwaddstr(wnd, row, 45, "unknown");
break;
case SENSOR_S_WARN:
mvwaddstr(wnd, row, 45, "WARNING");
break;
case SENSOR_S_CRIT:
mvwaddstr(wnd, row, 45, "CRITICAL");
break;
case SENSOR_S_OK:
mvwaddstr(wnd, row, 45, "OK");
break;
}
row++;
}
#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;
const 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";
} else if (in == 0 ){
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%lf %s" : "%s%.3lf %s",
signbit == -1 ? "-" : "", in, unit);
return outbuf;
}
int
cmdsensors(const char *cmd, char *args)
{
if (prefix(cmd, "type")) {
const char *t;
int i, has_type = 0;
for (i = 0; i < SENSOR_MAX_TYPES; ++i)
sensors_enabled[i] = 0;
while ((t = strsep(&args, " ")) != NULL) {
if (*t == '\0')
continue;
has_type = 1;
for (i = 0; i < SENSOR_MAX_TYPES; ++i) {
if (strcmp(t, sensor_type_s[i]) == 0) {
sensors_enabled[i] = 1;
break;
}
}
}
if (!has_type) {
for (i = 0; i < SENSOR_MAX_TYPES; ++i)
sensors_enabled[i] = 1;
}
} else if (prefix(cmd, "match")) {
const char *xname;
sensordev_xname_cnt = 0;
while ((xname = strsep(&args, " ")) != NULL) {
struct sensordev_xname *x;
int xname_len, cp_len;
xname_len = strlen(xname);
if (xname_len == 0)
continue;
x = &sensordev_xname[sensordev_xname_cnt];
x->flags = 0;
if (xname[xname_len - 1] == '*') {
--xname_len;
if (xname_len == 0)
continue;
x->flags |= XNAME_FLAG_WILDCARD;
}
cp_len = xname_len;
if (cp_len >= (int)sizeof(x->xname))
cp_len = sizeof(x->xname) - 1;
memcpy(x->xname, xname, cp_len);
x->xname[cp_len] = '\0';
x->xname_len = strlen(x->xname);
sensordev_xname_cnt++;
if (sensordev_xname_cnt == XNAME_MAX)
break;
}
}
wclear(wnd);
labelsensors();
refresh();
return (1);
}