summaryrefslogtreecommitdiff
path: root/usr.sbin/sensorsd/sensorsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sensorsd/sensorsd.c')
-rw-r--r--usr.sbin/sensorsd/sensorsd.c312
1 files changed, 312 insertions, 0 deletions
diff --git a/usr.sbin/sensorsd/sensorsd.c b/usr.sbin/sensorsd/sensorsd.c
new file mode 100644
index 00000000000..eb4fa26da67
--- /dev/null
+++ b/usr.sbin/sensorsd/sensorsd.c
@@ -0,0 +1,312 @@
+/* $OpenBSD: sensorsd.c,v 1.1 2003/09/24 20:32:49 henning Exp $ */
+
+/*
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sensors.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#define RFBUFSIZ 28 /* buffer size for print_sensor */
+#define RFBUFCNT 4 /* ring buffers */
+#define REPORT_FREQ 60 /* report every n seconds */
+#define CHECK_FREQ 60 /* check every n seconds */
+
+int main(int, char *[]);
+void check_sensors();
+void report(time_t);
+static char *print_sensor(enum sensor_type, u_int64_t);
+int parse_config(char *);
+int64_t get_val(char *, int, enum sensor_type);
+void reparse_cfg(int);
+
+enum sensor_status {
+ STATUS_OK,
+ STATUS_FAIL
+};
+
+struct limits_t {
+ TAILQ_ENTRY(limits_t) entries;
+ u_int8_t watch;
+ int num; /* sensor number */
+ enum sensor_type type; /* sensor type */
+ int64_t lower; /* lower limit */
+ int64_t upper; /* upper limit */
+ enum sensor_status status; /* last status */
+ time_t status_changed;
+ int64_t last_val;
+};
+
+TAILQ_HEAD(limits, limits_t) limits = TAILQ_HEAD_INITIALIZER(limits);
+
+char *configfile;
+int reload = 0;
+
+int
+main(int argc, char *argv[])
+{
+ struct sensor sensor;
+ struct limits_t *limit;
+ size_t len;
+ time_t next_report, last_report = 0;
+ time_t next_check;
+ int mib[3];
+ int i, sleeptime;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_SENSORS;
+ len = sizeof(sensor);
+
+ for (i = 0; i < 256; i++) {
+ mib[2] = i;
+ if (sysctl(mib, 3, &sensor, &len, NULL, 0) == -1) {
+ if (errno == ENXIO)
+ break;
+ else
+ err(1, "sysctl");
+ }
+ if ((limit = calloc(1, sizeof(struct limits_t))) == NULL)
+ err(1, "out of memory");
+ limit->num = i;
+ limit->type = sensor.type;
+ TAILQ_INSERT_TAIL(&limits, limit, entries);
+ }
+
+ if (i == 0)
+ errx(1, "no sensors found");
+
+ if (configfile == NULL)
+ if (asprintf(&configfile, "/etc/sensorsd.conf") == -1)
+ err(1, "out of memory");
+ if (parse_config(configfile))
+ errx(1, "error in config file");
+
+/* if (daemon(0, 0) == -1)
+ err(1, "unable to fork");
+*/
+ signal(SIGHUP, reparse_cfg);
+
+ syslog(LOG_INFO, "startup, monitoring %d sensors", i);
+
+ next_check = next_report = time(NULL);
+
+ for (;;) {
+ if (reload) {
+ if (parse_config(configfile))
+ syslog(LOG_CRIT, "error in config file %s",
+ configfile);
+ else
+ syslog(LOG_INFO, "configuration reloaded");
+ reload = 0;
+ }
+ if (next_check < time(NULL)) {
+ check_sensors();
+ next_check = time(NULL) + CHECK_FREQ;
+ }
+ if (next_report < time(NULL)) {
+ report(last_report);
+ last_report = next_report;
+ next_report = time(NULL) + REPORT_FREQ;
+ }
+ if (next_report < next_check)
+ sleeptime = next_report - time(NULL);
+ else
+ sleeptime = next_check - time(NULL);
+ if (sleeptime > 0)
+ sleep(sleeptime);
+ }
+}
+
+void
+check_sensors()
+{
+ struct sensor sensor;
+ struct limits_t *limit;
+ size_t len;
+ int mib[3];
+ int newstatus;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_SENSORS;
+ len = sizeof(sensor);
+
+ TAILQ_FOREACH(limit, &limits, entries)
+ if (limit->watch) {
+ mib[2] = limit->num;
+ if (sysctl(mib, 3, &sensor, &len, NULL, 0) == -1)
+ err(1, "sysctl");
+
+ limit->last_val = sensor.value;
+ if (sensor.value > limit->upper ||
+ sensor.value < limit->lower)
+ newstatus = STATUS_FAIL;
+ else
+ newstatus = STATUS_OK;
+
+ if (limit->status != newstatus) {
+ limit->status = newstatus;
+ limit->status_changed = time(NULL);
+ }
+ }
+}
+
+void
+report(time_t last_report)
+{
+ struct limits_t *limit = NULL;
+
+ TAILQ_FOREACH(limit, &limits, entries)
+ if (limit->status_changed > last_report) {
+ if (limit->status == STATUS_FAIL)
+ syslog(LOG_ALERT,
+ "failure for hw.sensors.%d: "
+ "%s not within limits",
+ limit->num,
+ print_sensor(limit->type, limit->last_val));
+ else
+ syslog(LOG_ALERT,
+ "hw.sensors.%d within limits again, "
+ "current value %s",
+ limit->num,
+ print_sensor(limit->type, limit->last_val));
+ }
+}
+
+static char *
+print_sensor(enum sensor_type type, u_int64_t value)
+{
+ static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */
+ static int idx;
+ char *fbuf;
+
+ fbuf = rfbuf[idx++];
+ if (idx == RFBUFCNT)
+ idx = 0;
+
+ switch (type) {
+ case SENSOR_TEMP:
+ snprintf(fbuf, RFBUFSIZ, "%.2fC/%.2fF",
+ (value / 1000 / 1000) - 273.16,
+ ((value / 1000 / 1000) - 273.16) * 9 / 5 + 32);
+ break;
+ case SENSOR_FANRPM:
+ snprintf(fbuf, RFBUFSIZ, "%lld RPM", value);
+ break;
+ case SENSOR_VOLTS_DC:
+ snprintf(fbuf, RFBUFSIZ, "%.2fV", value / 1000.0 / 1000.0);
+ break;
+ default:
+ snprintf(fbuf, RFBUFSIZ, "%lld ???", value);
+ }
+
+ return (fbuf);
+}
+
+int
+parse_config(char *cf)
+{
+ struct limits_t *p, *next;
+ char *buf = NULL, *ebuf = NULL;
+ char node[24];
+ char **cfa;
+
+ cfa = calloc(2, sizeof(char *));
+ cfa[0] = cf;
+ cfa[1] = NULL;
+
+ for (p = TAILQ_FIRST(&limits); p != NULL; p = next) {
+ next = TAILQ_NEXT(p, entries);
+ snprintf(node, sizeof(node), "hw.sensors.%d", p->num);
+ if (cgetent(&buf, cfa, node) != 0)
+ p->watch = 0;
+ else {
+ p->watch = 1;
+ if (cgetstr(buf, "low", &ebuf) < 0)
+ ebuf = NULL;
+ p->lower = get_val(ebuf, 0, p->type);
+ if (cgetstr(buf, "high", &ebuf) < 0)
+ ebuf = NULL;
+ p->upper = get_val(ebuf, 1, p->type);
+ free(buf);
+ buf = NULL;
+ }
+ }
+ free(cfa);
+ return (0);
+}
+
+int64_t
+get_val(char *buf, int upper, enum sensor_type type)
+{
+ double val;
+ int64_t rval = 0;
+ char *p;
+
+ if (buf == NULL) {
+ if (upper)
+ return (LLONG_MAX);
+ else
+ return (LLONG_MIN);
+ }
+
+ val = strtod(buf, &p);
+ if (buf == p)
+ err(1, "incorrect value: %s", buf);
+
+ switch(type) {
+ case SENSOR_TEMP:
+ switch(*p) {
+ case 'C':
+ printf ("C");
+ rval = (val + 273.16) * 1000 * 1000;
+ break;
+ case 'F':
+ printf("F");
+ rval = ((val - 32.0) / 9 * 5 + 273.16) * 1000 * 1000;
+ break;
+ default:
+ errx(1, "unknown unit %s for temp sensor", p);
+ }
+ break;
+ case SENSOR_FANRPM:
+ rval = val;
+ break;
+ case SENSOR_VOLTS_DC:
+ if (*p != 'V')
+ errx(1, "unknown unit %s for voltage sensor", p);
+ rval = val * 1000 * 1000;
+ break;
+ }
+ free(buf);
+ return (rval);
+}
+
+void
+reparse_cfg(int signum)
+{
+ reload = 1;
+}