drm/radeon: Reduce differences with Linux 3.18
[dragonfly.git] / usr.sbin / sensorsd / sensorsd.c
blob095ba1da42f051f358e807e38078bd54b3c58d9a
1 /* $OpenBSD: sensorsd.c,v 1.46 2008/06/14 00:16:10 cnst Exp $ */
3 /*
4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2005 Matthew Gream <matthew.gream@pobox.com>
6 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
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.
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.
21 #include <sys/param.h>
22 #include <sys/sysctl.h>
23 #include <sys/sensors.h>
25 #include <err.h>
26 #include <errno.h>
27 #include <inttypes.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <time.h>
34 #include <unistd.h>
36 #define RFBUFSIZ 28 /* buffer size for print_sensor */
37 #define RFBUFCNT 4 /* ring buffers */
38 #define CHECK_PERIOD 20 /* check every n seconds */
40 enum sensorsd_s_status {
41 SENSORSD_S_UNSPEC, /* status is unspecified */
42 SENSORSD_S_INVALID, /* status is invalid, per SENSOR_FINVALID */
43 SENSORSD_S_WITHIN, /* status is within limits */
44 SENSORSD_S_ABOVE, /* status is above the higher limit */
45 SENSORSD_S_BELOW /* status is below the lower limit */
48 struct limits_t {
49 TAILQ_ENTRY(limits_t) entries;
50 enum sensor_type type; /* sensor type */
51 int numt; /* sensor number */
52 int64_t last_val;
53 int64_t lower; /* lower limit */
54 int64_t upper; /* upper limit */
55 char *command; /* failure command */
56 time_t astatus_changed;
57 time_t ustatus_changed;
58 enum sensor_status astatus; /* last automatic status */
59 enum sensor_status astatus2;
60 enum sensorsd_s_status ustatus; /* last user-limit status */
61 enum sensorsd_s_status ustatus2;
62 int acount; /* stat change counter */
63 int ucount; /* stat change counter */
64 u_int8_t flags; /* sensorsd limit flags */
65 #define SENSORSD_L_USERLIMIT 0x0001 /* user specified limit */
66 #define SENSORSD_L_ISTATUS 0x0002 /* ignore automatic status */
69 struct sdlim_t {
70 TAILQ_ENTRY(sdlim_t) entries;
71 char dxname[16]; /* device unix name */
72 int dev; /* device number */
73 int sensor_cnt;
74 TAILQ_HEAD(, limits_t) limits;
77 static void usage(void) __dead2;
78 static void create(void);
79 static struct sdlim_t *create_sdlim(struct sensordev *);
80 static void destroy_sdlim(struct sdlim_t *);
81 static void check(time_t);
82 static void check_sdlim(struct sdlim_t *, time_t);
83 static void execute(char *);
84 static void report(time_t);
85 static void report_sdlim(struct sdlim_t *, time_t);
86 static char *print_sensor(enum sensor_type, int64_t);
87 static void parse_config(char *);
88 static void parse_config_sdlim(struct sdlim_t *, char *);
89 static int64_t get_val(char *, int, enum sensor_type);
90 static void reparse_cfg(int);
92 TAILQ_HEAD(sdlimhead_t, sdlim_t);
93 static struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims);
95 static char *configfile;
96 static volatile sig_atomic_t reload = 0;
97 static int debug = 0;
99 static void
100 usage(void)
102 fprintf(stderr, "usage: %s [-d] [-c check]\n", getprogname());
103 exit(1);
107 main(int argc, char *argv[])
109 time_t last_report = 0, this_check;
110 int ch, check_period = CHECK_PERIOD;
111 const char *errstr;
113 while ((ch = getopt(argc, argv, "c:d")) != -1) {
114 switch (ch) {
115 case 'c':
116 check_period = strtonum(optarg, 1, 600, &errstr);
117 if (errstr)
118 errx(1, "check %s", errstr);
119 break;
120 case 'd':
121 debug = 1;
122 break;
123 default:
124 usage();
128 argc -= optind;
129 argv += optind;
130 if (argc > 0)
131 usage();
133 openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
135 create();
137 if (configfile == NULL)
138 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1)
139 err(1, "out of memory");
140 parse_config(configfile);
142 if (debug == 0 && daemon(0, 0) == -1)
143 err(1, "unable to fork");
145 signal(SIGHUP, reparse_cfg);
146 signal(SIGCHLD, SIG_IGN);
148 for (;;) {
149 if (reload) {
150 parse_config(configfile);
151 syslog(LOG_INFO, "configuration reloaded");
152 reload = 0;
154 this_check = time(NULL);
155 if (!(last_report < this_check))
156 this_check = last_report + 1;
157 check(this_check);
158 report(last_report);
159 last_report = this_check;
160 sleep(check_period);
164 static void
165 create(void)
167 struct sensordev sensordev;
168 struct sdlim_t *sdlim;
169 size_t sdlen = sizeof(sensordev);
170 int mib[3], dev, sensor_cnt = 0;
172 mib[0] = CTL_HW;
173 mib[1] = HW_SENSORS;
175 for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
176 mib[2] = dev;
177 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
178 if (errno != ENOENT)
179 warn("sysctl");
180 continue;
182 sdlim = create_sdlim(&sensordev);
183 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries);
184 sensor_cnt += sdlim->sensor_cnt;
187 syslog(LOG_INFO, "startup, system has %d sensors", sensor_cnt);
190 static struct sdlim_t *
191 create_sdlim(struct sensordev *snsrdev)
193 struct sensor sensor;
194 struct sdlim_t *sdlim;
195 struct limits_t *limit;
196 size_t slen = sizeof(sensor);
197 int mib[5], numt;
198 enum sensor_type type;
200 if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL)
201 err(1, "calloc");
203 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname));
205 mib[0] = CTL_HW;
206 mib[1] = HW_SENSORS;
207 mib[2] = sdlim->dev = snsrdev->num;
209 TAILQ_INIT(&sdlim->limits);
211 for (type = 0; type < SENSOR_MAX_TYPES; type++) {
212 mib[3] = type;
213 for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
214 mib[4] = numt;
215 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
216 if (errno != ENOENT)
217 warn("sysctl");
218 continue;
220 if ((limit = calloc(1, sizeof(struct limits_t))) ==
221 NULL)
222 err(1, "calloc");
223 limit->type = type;
224 limit->numt = numt;
225 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries);
226 sdlim->sensor_cnt++;
230 return (sdlim);
233 static void
234 destroy_sdlim(struct sdlim_t *sdlim)
236 struct limits_t *limit;
238 while((limit = TAILQ_FIRST(&sdlim->limits)) != NULL) {
239 TAILQ_REMOVE(&sdlim->limits, limit, entries);
240 if (limit->command != NULL)
241 free(limit->command);
242 free(limit);
244 free(sdlim);
247 static void
248 check(time_t this_check)
250 struct sensordev sensordev;
251 struct sdlim_t *sdlim, *next;
252 int mib[3];
253 int h, t, i;
254 size_t sdlen = sizeof(sensordev);
256 if (TAILQ_EMPTY(&sdlims)) {
257 h = 0;
258 t = -1;
259 } else {
260 h = TAILQ_FIRST(&sdlims)->dev;
261 t = TAILQ_LAST(&sdlims, sdlimhead_t)->dev;
263 sdlim = TAILQ_FIRST(&sdlims);
265 mib[0] = CTL_HW;
266 mib[1] = HW_SENSORS;
267 /* look ahead for 4 more sensordevs */
268 for (i = h; i <= t + 4; i++) {
269 if (sdlim != NULL && i > sdlim->dev)
270 sdlim = TAILQ_NEXT(sdlim, entries);
271 if (sdlim == NULL && i <= t)
272 syslog(LOG_ALERT, "inconsistent sdlim logic");
273 mib[2] = i;
274 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
275 if (errno != ENOENT)
276 warn("sysctl");
277 if (sdlim != NULL && i == sdlim->dev) {
278 next = TAILQ_NEXT(sdlim, entries);
279 TAILQ_REMOVE(&sdlims, sdlim, entries);
280 syslog(LOG_INFO, "%s has disappeared",
281 sdlim->dxname);
282 destroy_sdlim(sdlim);
283 sdlim = next;
285 continue;
287 if (sdlim != NULL && i == sdlim->dev) {
288 if (strcmp(sdlim->dxname, sensordev.xname) == 0) {
289 check_sdlim(sdlim, this_check);
290 continue;
291 } else {
292 next = TAILQ_NEXT(sdlim, entries);
293 TAILQ_REMOVE(&sdlims, sdlim, entries);
294 syslog(LOG_INFO, "%s has been replaced",
295 sdlim->dxname);
296 destroy_sdlim(sdlim);
297 sdlim = next;
300 next = create_sdlim(&sensordev);
301 /* inserting next before sdlim */
302 if (sdlim != NULL)
303 TAILQ_INSERT_BEFORE(sdlim, next, entries);
304 else
305 TAILQ_INSERT_TAIL(&sdlims, next, entries);
306 syslog(LOG_INFO, "%s has appeared", next->dxname);
307 sdlim = next;
308 parse_config_sdlim(sdlim, configfile);
309 check_sdlim(sdlim, this_check);
312 if (TAILQ_EMPTY(&sdlims))
313 return;
314 /* Ensure that our queue is consistent. */
315 for (sdlim = TAILQ_FIRST(&sdlims);
316 (next = TAILQ_NEXT(sdlim, entries)) != NULL;
317 sdlim = next)
318 if (sdlim->dev > next->dev)
319 syslog(LOG_ALERT, "inconsistent sdlims queue");
322 static void
323 check_sdlim(struct sdlim_t *sdlim, time_t this_check)
325 struct sensor sensor;
326 struct limits_t *limit;
327 size_t len;
328 int mib[5];
330 mib[0] = CTL_HW;
331 mib[1] = HW_SENSORS;
332 mib[2] = sdlim->dev;
333 len = sizeof(sensor);
335 TAILQ_FOREACH(limit, &sdlim->limits, entries) {
336 if ((limit->flags & SENSORSD_L_ISTATUS) &&
337 !(limit->flags & SENSORSD_L_USERLIMIT))
338 continue;
340 mib[3] = limit->type;
341 mib[4] = limit->numt;
342 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1)
343 err(1, "sysctl");
345 if (!(limit->flags & SENSORSD_L_ISTATUS)) {
346 enum sensor_status newastatus = sensor.status;
348 if (limit->astatus != newastatus) {
349 if (limit->astatus2 != newastatus) {
350 limit->astatus2 = newastatus;
351 limit->acount = 0;
352 } else if (++limit->acount >= 3) {
353 limit->last_val = sensor.value;
354 limit->astatus2 =
355 limit->astatus = newastatus;
356 limit->astatus_changed = this_check;
361 if (limit->flags & SENSORSD_L_USERLIMIT) {
362 enum sensorsd_s_status newustatus;
364 if (sensor.flags & SENSOR_FINVALID)
365 newustatus = SENSORSD_S_INVALID;
366 else if (sensor.value > limit->upper)
367 newustatus = SENSORSD_S_ABOVE;
368 else if (sensor.value < limit->lower)
369 newustatus = SENSORSD_S_BELOW;
370 else
371 newustatus = SENSORSD_S_WITHIN;
373 if (limit->ustatus != newustatus) {
374 if (limit->ustatus2 != newustatus) {
375 limit->ustatus2 = newustatus;
376 limit->ucount = 0;
377 } else if (++limit->ucount >= 3) {
378 limit->last_val = sensor.value;
379 limit->ustatus2 =
380 limit->ustatus = newustatus;
381 limit->ustatus_changed = this_check;
388 static void
389 execute(char *command)
391 const char *argp[] = {"sh", "-c", command, NULL};
393 switch (fork()) {
394 case -1:
395 syslog(LOG_CRIT, "execute: fork() failed");
396 break;
397 case 0:
398 execv("/bin/sh", __DECONST(char **, argp));
399 _exit(1);
400 /* NOTREACHED */
401 default:
402 break;
406 static void
407 report(time_t last_report)
409 struct sdlim_t *sdlim;
411 TAILQ_FOREACH(sdlim, &sdlims, entries)
412 report_sdlim(sdlim, last_report);
415 static void
416 report_sdlim(struct sdlim_t *sdlim, time_t last_report)
418 struct limits_t *limit;
420 TAILQ_FOREACH(limit, &sdlim->limits, entries) {
421 if ((limit->astatus_changed <= last_report) &&
422 (limit->ustatus_changed <= last_report))
423 continue;
425 if (limit->astatus_changed > last_report) {
426 const char *as = NULL;
428 switch (limit->astatus) {
429 case SENSOR_S_UNSPEC:
430 as = "";
431 break;
432 case SENSOR_S_OK:
433 as = ", OK";
434 break;
435 case SENSOR_S_WARN:
436 as = ", WARN";
437 break;
438 case SENSOR_S_CRIT:
439 as = ", CRITICAL";
440 break;
441 case SENSOR_S_UNKNOWN:
442 as = ", UNKNOWN";
443 break;
445 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO :
446 LOG_ALERT, "%s.%s%d: %s%s",
447 sdlim->dxname, sensor_type_s[limit->type],
448 limit->numt,
449 print_sensor(limit->type, limit->last_val), as);
452 if (limit->ustatus_changed > last_report) {
453 char us[BUFSIZ];
455 switch (limit->ustatus) {
456 case SENSORSD_S_UNSPEC:
457 snprintf(us, sizeof(us),
458 "ustatus uninitialised");
459 break;
460 case SENSORSD_S_INVALID:
461 snprintf(us, sizeof(us), "marked invalid");
462 break;
463 case SENSORSD_S_WITHIN:
464 snprintf(us, sizeof(us), "within limits: %s",
465 print_sensor(limit->type, limit->last_val));
466 break;
467 case SENSORSD_S_ABOVE:
468 snprintf(us, sizeof(us), "exceeds limits: %s is above %s",
469 print_sensor(limit->type, limit->last_val),
470 print_sensor(limit->type, limit->upper));
471 break;
472 case SENSORSD_S_BELOW:
473 snprintf(us, sizeof(us), "exceeds limits: %s is below %s",
474 print_sensor(limit->type, limit->last_val),
475 print_sensor(limit->type, limit->lower));
476 break;
478 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO :
479 LOG_ALERT, "%s.%s%d: %s",
480 sdlim->dxname, sensor_type_s[limit->type],
481 limit->numt, us);
484 if (limit->command) {
485 int i = 0, n = 0, r;
486 char *cmd = limit->command;
487 char buf[BUFSIZ];
488 int len = sizeof(buf);
490 buf[0] = '\0';
491 for (i = n = 0; n < len; ++i) {
492 if (cmd[i] == '\0') {
493 buf[n++] = '\0';
494 break;
496 if (cmd[i] != '%') {
497 buf[n++] = limit->command[i];
498 continue;
500 i++;
501 if (cmd[i] == '\0') {
502 buf[n++] = '\0';
503 break;
506 switch (cmd[i]) {
507 case 'x':
508 r = snprintf(&buf[n], len - n, "%s",
509 sdlim->dxname);
510 break;
511 case 't':
512 r = snprintf(&buf[n], len - n, "%s",
513 sensor_type_s[limit->type]);
514 break;
515 case 'n':
516 r = snprintf(&buf[n], len - n, "%d",
517 limit->numt);
518 break;
519 case 'l':
521 const char *s = "";
522 switch(limit->ustatus){
523 case SENSORSD_S_UNSPEC:
524 s = "uninitialised";
525 break;
526 case SENSORSD_S_INVALID:
527 s = "invalid";
528 break;
529 case SENSORSD_S_WITHIN:
530 s = "within";
531 break;
532 case SENSORSD_S_ABOVE:
533 s = "above";
534 break;
535 case SENSORSD_S_BELOW:
536 s = "below";
537 break;
539 r = snprintf(&buf[n], len - n, "%s",
541 break;
543 case 's':
545 const char *s;
546 switch(limit->astatus){
547 case SENSOR_S_UNSPEC:
548 s = "UNSPEC";
549 break;
550 case SENSOR_S_OK:
551 s = "OK";
552 break;
553 case SENSOR_S_WARN:
554 s = "WARNING";
555 break;
556 case SENSOR_S_CRIT:
557 s = "CRITICAL";
558 break;
559 default:
560 s = "UNKNOWN";
562 r = snprintf(&buf[n], len - n, "%s",
564 break;
566 case '2':
567 r = snprintf(&buf[n], len - n, "%s",
568 print_sensor(limit->type,
569 limit->last_val));
570 break;
571 case '3':
572 r = snprintf(&buf[n], len - n, "%s",
573 print_sensor(limit->type,
574 limit->lower));
575 break;
576 case '4':
577 r = snprintf(&buf[n], len - n, "%s",
578 print_sensor(limit->type,
579 limit->upper));
580 break;
581 default:
582 r = snprintf(&buf[n], len - n, "%%%c",
583 cmd[i]);
584 break;
586 if (r < 0 || (r >= len - n)) {
587 syslog(LOG_CRIT, "could not parse "
588 "command");
589 return;
591 if (r > 0)
592 n += r;
594 if (buf[0])
595 execute(buf);
600 static const char *drvstat[] = {
601 NULL, "empty", "ready", "powerup", "online", "idle", "active",
602 "rebuild", "powerdown", "fail", "pfail"
605 static char *
606 print_sensor(enum sensor_type type, int64_t value)
608 static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */
609 static int idx;
610 char *fbuf;
612 fbuf = rfbuf[idx++];
613 if (idx == RFBUFCNT)
614 idx = 0;
616 switch (type) {
617 case SENSOR_TEMP:
618 snprintf(fbuf, RFBUFSIZ, "%.2f degC",
619 (value - 273150000) / 1000000.0);
620 break;
621 case SENSOR_FANRPM:
622 snprintf(fbuf, RFBUFSIZ, "%"PRId64" RPM", value);
623 break;
624 case SENSOR_VOLTS_DC:
625 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0);
626 break;
627 case SENSOR_AMPS:
628 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0);
629 break;
630 case SENSOR_WATTHOUR:
631 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0);
632 break;
633 case SENSOR_AMPHOUR:
634 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0);
635 break;
636 case SENSOR_INDICATOR:
637 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off");
638 break;
639 case SENSOR_FREQ:
640 snprintf(fbuf, RFBUFSIZ, "%"PRId64" Hz", value);
641 break;
642 case SENSOR_ECC:
643 case SENSOR_INTEGER:
644 snprintf(fbuf, RFBUFSIZ, "%"PRId64, value);
645 break;
646 case SENSOR_PERCENT:
647 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0);
648 break;
649 case SENSOR_LUX:
650 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0);
651 break;
652 case SENSOR_DRIVE:
653 if (0 < value && value < (int64_t)NELEM(drvstat))
654 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]);
655 else
656 snprintf(fbuf, RFBUFSIZ, "%"PRId64" ???", value);
657 break;
658 case SENSOR_TIMEDELTA:
659 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0);
660 break;
661 default:
662 snprintf(fbuf, RFBUFSIZ, "%"PRId64" ???", value);
665 return (fbuf);
668 static void
669 parse_config(char *cf)
671 struct sdlim_t *sdlim;
673 TAILQ_FOREACH(sdlim, &sdlims, entries)
674 parse_config_sdlim(sdlim, cf);
677 static void
678 parse_config_sdlim(struct sdlim_t *sdlim, char *cf)
680 struct limits_t *p;
681 char *buf = NULL, *ebuf = NULL;
682 char node[48];
683 char *cfa[2];
685 cfa[0] = cf;
686 cfa[1] = NULL;
688 TAILQ_FOREACH(p, &sdlim->limits, entries) {
689 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d",
690 sdlim->dxname, sensor_type_s[p->type], p->numt);
691 p->flags = 0;
692 if (cgetent(&buf, cfa, node) != 0)
693 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0)
694 continue;
695 if (cgetcap(buf, "istatus", ':'))
696 p->flags |= SENSORSD_L_ISTATUS;
697 if (cgetstr(buf, "low", &ebuf) < 0)
698 ebuf = NULL;
699 p->lower = get_val(ebuf, 0, p->type);
700 if (cgetstr(buf, "high", &ebuf) < 0)
701 ebuf = NULL;
702 p->upper = get_val(ebuf, 1, p->type);
703 if (cgetstr(buf, "command", &ebuf) < 0)
704 ebuf = NULL;
705 if (ebuf)
706 asprintf(&(p->command), "%s", ebuf);
707 free(buf);
708 buf = NULL;
709 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX)
710 p->flags |= SENSORSD_L_USERLIMIT;
714 static int64_t
715 get_val(char *buf, int upper, enum sensor_type type)
717 double val;
718 int64_t rval = 0;
719 char *p;
721 if (buf == NULL) {
722 if (upper)
723 return (LLONG_MAX);
724 else
725 return (LLONG_MIN);
728 val = strtod(buf, &p);
729 if (buf == p)
730 err(1, "incorrect value: %s", buf);
732 switch(type) {
733 case SENSOR_TEMP:
734 switch(*p) {
735 case 'C':
736 printf("C");
737 rval = val * 1000 * 1000 + 273150000;
738 break;
739 case 'F':
740 printf("F");
741 rval = (val * 1000 * 1000 + 459670000) / 9 * 5;
742 break;
743 default:
744 errx(1, "unknown unit %s for temp sensor", p);
746 break;
747 case SENSOR_FANRPM:
748 rval = val;
749 break;
750 case SENSOR_VOLTS_DC:
751 if (*p != 'V')
752 errx(1, "unknown unit %s for voltage sensor", p);
753 rval = val * 1000 * 1000;
754 break;
755 case SENSOR_PERCENT:
756 rval = val * 1000.0;
757 break;
758 case SENSOR_FREQ:
759 case SENSOR_ECC:
760 case SENSOR_INDICATOR:
761 case SENSOR_INTEGER:
762 case SENSOR_DRIVE:
763 rval = val;
764 break;
765 case SENSOR_AMPS:
766 case SENSOR_WATTHOUR:
767 case SENSOR_AMPHOUR:
768 case SENSOR_LUX:
769 rval = val * 1000 * 1000;
770 break;
771 case SENSOR_TIMEDELTA:
772 rval = val * 1000 * 1000 * 1000;
773 break;
774 default:
775 errx(1, "unsupported sensor type");
776 /* not reached */
778 free(buf);
779 return (rval);
782 /* ARGSUSED */
783 static void
784 reparse_cfg(__unused int signo)
786 reload = 1;