Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / usr.sbin / sensorsd / sensorsd.c
blobd1b67c8d38a93934a0ca3f3370b8c25e5ae45435
1 /* $OpenBSD: sensorsd.c,v 1.46 2008/06/14 00:16:10 cnst Exp $ */
2 /* $DragonFly: src/usr.sbin/sensorsd/sensorsd.c,v 1.2 2008/10/19 08:16:20 hasso Exp $ */
4 /*
5 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
6 * Copyright (c) 2005 Matthew Gream <matthew.gream@pobox.com>
7 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
24 #include <sys/sensors.h>
26 #include <err.h>
27 #include <errno.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 void usage(void);
78 void create(void);
79 struct sdlim_t *create_sdlim(struct sensordev *);
80 void destroy_sdlim(struct sdlim_t *);
81 void check(time_t);
82 void check_sdlim(struct sdlim_t *, time_t);
83 void execute(char *);
84 void report(time_t);
85 void report_sdlim(struct sdlim_t *, time_t);
86 static char *print_sensor(enum sensor_type, int64_t);
87 void parse_config(char *);
88 void parse_config_sdlim(struct sdlim_t *, char *);
89 int64_t get_val(char *, int, enum sensor_type);
90 void reparse_cfg(int);
92 TAILQ_HEAD(sdlimhead_t, sdlim_t);
93 struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims);
95 char *configfile;
96 volatile sig_atomic_t reload = 0;
97 int debug = 0;
99 void
100 usage(void)
102 extern char *__progname;
103 fprintf(stderr, "usage: %s [-d] [-c check]\n", __progname);
104 exit(1);
108 main(int argc, char *argv[])
110 time_t last_report = 0, this_check;
111 int ch, check_period = CHECK_PERIOD;
112 const char *errstr;
114 while ((ch = getopt(argc, argv, "c:d")) != -1) {
115 switch (ch) {
116 case 'c':
117 check_period = strtonum(optarg, 1, 600, &errstr);
118 if (errstr)
119 errx(1, "check %s", errstr);
120 break;
121 case 'd':
122 debug = 1;
123 break;
124 default:
125 usage();
129 argc -= optind;
130 argv += optind;
131 if (argc > 0)
132 usage();
134 openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
136 create();
138 if (configfile == NULL)
139 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1)
140 err(1, "out of memory");
141 parse_config(configfile);
143 if (debug == 0 && daemon(0, 0) == -1)
144 err(1, "unable to fork");
146 signal(SIGHUP, reparse_cfg);
147 signal(SIGCHLD, SIG_IGN);
149 for (;;) {
150 if (reload) {
151 parse_config(configfile);
152 syslog(LOG_INFO, "configuration reloaded");
153 reload = 0;
155 this_check = time(NULL);
156 if (!(last_report < this_check))
157 this_check = last_report + 1;
158 check(this_check);
159 report(last_report);
160 last_report = this_check;
161 sleep(check_period);
165 void
166 create(void)
168 struct sensordev sensordev;
169 struct sdlim_t *sdlim;
170 size_t sdlen = sizeof(sensordev);
171 int mib[3], dev, sensor_cnt = 0;
173 mib[0] = CTL_HW;
174 mib[1] = HW_SENSORS;
176 for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
177 mib[2] = dev;
178 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
179 if (errno != ENOENT)
180 warn("sysctl");
181 continue;
183 sdlim = create_sdlim(&sensordev);
184 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries);
185 sensor_cnt += sdlim->sensor_cnt;
188 syslog(LOG_INFO, "startup, system has %d sensors", sensor_cnt);
191 struct sdlim_t *
192 create_sdlim(struct sensordev *snsrdev)
194 struct sensor sensor;
195 struct sdlim_t *sdlim;
196 struct limits_t *limit;
197 size_t slen = sizeof(sensor);
198 int mib[5], numt;
199 enum sensor_type type;
201 if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL)
202 err(1, "calloc");
204 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname));
206 mib[0] = CTL_HW;
207 mib[1] = HW_SENSORS;
208 mib[2] = sdlim->dev = snsrdev->num;
210 TAILQ_INIT(&sdlim->limits);
212 for (type = 0; type < SENSOR_MAX_TYPES; type++) {
213 mib[3] = type;
214 for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
215 mib[4] = numt;
216 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) {
217 if (errno != ENOENT)
218 warn("sysctl");
219 continue;
221 if ((limit = calloc(1, sizeof(struct limits_t))) ==
222 NULL)
223 err(1, "calloc");
224 limit->type = type;
225 limit->numt = numt;
226 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries);
227 sdlim->sensor_cnt++;
231 return (sdlim);
234 void
235 destroy_sdlim(struct sdlim_t *sdlim)
237 struct limits_t *limit;
239 while((limit = TAILQ_FIRST(&sdlim->limits)) != NULL) {
240 TAILQ_REMOVE(&sdlim->limits, limit, entries);
241 if (limit->command != NULL)
242 free(limit->command);
243 free(limit);
245 free(sdlim);
248 void
249 check(time_t this_check)
251 struct sensordev sensordev;
252 struct sdlim_t *sdlim, *next;
253 int mib[3];
254 int h, t, i;
255 size_t sdlen = sizeof(sensordev);
257 if (TAILQ_EMPTY(&sdlims)) {
258 h = 0;
259 t = -1;
260 } else {
261 h = TAILQ_FIRST(&sdlims)->dev;
262 t = TAILQ_LAST(&sdlims, sdlimhead_t)->dev;
264 sdlim = TAILQ_FIRST(&sdlims);
266 mib[0] = CTL_HW;
267 mib[1] = HW_SENSORS;
268 /* look ahead for 4 more sensordevs */
269 for (i = h; i <= t + 4; i++) {
270 if (sdlim != NULL && i > sdlim->dev)
271 sdlim = TAILQ_NEXT(sdlim, entries);
272 if (sdlim == NULL && i <= t)
273 syslog(LOG_ALERT, "inconsistent sdlim logic");
274 mib[2] = i;
275 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
276 if (errno != ENOENT)
277 warn("sysctl");
278 if (sdlim != NULL && i == sdlim->dev) {
279 next = TAILQ_NEXT(sdlim, entries);
280 TAILQ_REMOVE(&sdlims, sdlim, entries);
281 syslog(LOG_INFO, "%s has disappeared",
282 sdlim->dxname);
283 destroy_sdlim(sdlim);
284 sdlim = next;
286 continue;
288 if (sdlim != NULL && i == sdlim->dev) {
289 if (strcmp(sdlim->dxname, sensordev.xname) == 0) {
290 check_sdlim(sdlim, this_check);
291 continue;
292 } else {
293 next = TAILQ_NEXT(sdlim, entries);
294 TAILQ_REMOVE(&sdlims, sdlim, entries);
295 syslog(LOG_INFO, "%s has been replaced",
296 sdlim->dxname);
297 destroy_sdlim(sdlim);
298 sdlim = next;
301 next = create_sdlim(&sensordev);
302 /* inserting next before sdlim */
303 if (sdlim != NULL)
304 TAILQ_INSERT_BEFORE(sdlim, next, entries);
305 else
306 TAILQ_INSERT_TAIL(&sdlims, next, entries);
307 syslog(LOG_INFO, "%s has appeared", next->dxname);
308 sdlim = next;
309 parse_config_sdlim(sdlim, configfile);
310 check_sdlim(sdlim, this_check);
313 if (TAILQ_EMPTY(&sdlims))
314 return;
315 /* Ensure that our queue is consistent. */
316 for (sdlim = TAILQ_FIRST(&sdlims);
317 (next = TAILQ_NEXT(sdlim, entries)) != NULL;
318 sdlim = next)
319 if (sdlim->dev > next->dev)
320 syslog(LOG_ALERT, "inconsistent sdlims queue");
323 void
324 check_sdlim(struct sdlim_t *sdlim, time_t this_check)
326 struct sensor sensor;
327 struct limits_t *limit;
328 size_t len;
329 int mib[5];
331 mib[0] = CTL_HW;
332 mib[1] = HW_SENSORS;
333 mib[2] = sdlim->dev;
334 len = sizeof(sensor);
336 TAILQ_FOREACH(limit, &sdlim->limits, entries) {
337 if ((limit->flags & SENSORSD_L_ISTATUS) &&
338 !(limit->flags & SENSORSD_L_USERLIMIT))
339 continue;
341 mib[3] = limit->type;
342 mib[4] = limit->numt;
343 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1)
344 err(1, "sysctl");
346 if (!(limit->flags & SENSORSD_L_ISTATUS)) {
347 enum sensor_status newastatus = sensor.status;
349 if (limit->astatus != newastatus) {
350 if (limit->astatus2 != newastatus) {
351 limit->astatus2 = newastatus;
352 limit->acount = 0;
353 } else if (++limit->acount >= 3) {
354 limit->last_val = sensor.value;
355 limit->astatus2 =
356 limit->astatus = newastatus;
357 limit->astatus_changed = this_check;
362 if (limit->flags & SENSORSD_L_USERLIMIT) {
363 enum sensorsd_s_status newustatus;
365 if (sensor.flags & SENSOR_FINVALID)
366 newustatus = SENSORSD_S_INVALID;
367 else if (sensor.value > limit->upper)
368 newustatus = SENSORSD_S_ABOVE;
369 else if (sensor.value < limit->lower)
370 newustatus = SENSORSD_S_BELOW;
371 else
372 newustatus = SENSORSD_S_WITHIN;
374 if (limit->ustatus != newustatus) {
375 if (limit->ustatus2 != newustatus) {
376 limit->ustatus2 = newustatus;
377 limit->ucount = 0;
378 } else if (++limit->ucount >= 3) {
379 limit->last_val = sensor.value;
380 limit->ustatus2 =
381 limit->ustatus = newustatus;
382 limit->ustatus_changed = this_check;
389 void
390 execute(char *command)
392 char *argp[] = {"sh", "-c", command, NULL};
394 switch (fork()) {
395 case -1:
396 syslog(LOG_CRIT, "execute: fork() failed");
397 break;
398 case 0:
399 execv("/bin/sh", argp);
400 _exit(1);
401 /* NOTREACHED */
402 default:
403 break;
407 void
408 report(time_t last_report)
410 struct sdlim_t *sdlim;
412 TAILQ_FOREACH(sdlim, &sdlims, entries)
413 report_sdlim(sdlim, last_report);
416 void
417 report_sdlim(struct sdlim_t *sdlim, time_t last_report)
419 struct limits_t *limit;
421 TAILQ_FOREACH(limit, &sdlim->limits, entries) {
422 if ((limit->astatus_changed <= last_report) &&
423 (limit->ustatus_changed <= last_report))
424 continue;
426 if (limit->astatus_changed > last_report) {
427 const char *as = NULL;
429 switch (limit->astatus) {
430 case SENSOR_S_UNSPEC:
431 as = "";
432 break;
433 case SENSOR_S_OK:
434 as = ", OK";
435 break;
436 case SENSOR_S_WARN:
437 as = ", WARN";
438 break;
439 case SENSOR_S_CRIT:
440 as = ", CRITICAL";
441 break;
442 case SENSOR_S_UNKNOWN:
443 as = ", UNKNOWN";
444 break;
446 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO :
447 LOG_ALERT, "%s.%s%d: %s%s",
448 sdlim->dxname, sensor_type_s[limit->type],
449 limit->numt,
450 print_sensor(limit->type, limit->last_val), as);
453 if (limit->ustatus_changed > last_report) {
454 char us[BUFSIZ];
456 switch (limit->ustatus) {
457 case SENSORSD_S_UNSPEC:
458 snprintf(us, sizeof(us),
459 "ustatus uninitialised");
460 break;
461 case SENSORSD_S_INVALID:
462 snprintf(us, sizeof(us), "marked invalid");
463 break;
464 case SENSORSD_S_WITHIN:
465 snprintf(us, sizeof(us), "within limits: %s",
466 print_sensor(limit->type, limit->last_val));
467 break;
468 case SENSORSD_S_ABOVE:
469 snprintf(us, sizeof(us), "exceeds limits: %s is above %s",
470 print_sensor(limit->type, limit->last_val),
471 print_sensor(limit->type, limit->upper));
472 break;
473 case SENSORSD_S_BELOW:
474 snprintf(us, sizeof(us), "exceeds limits: %s is below %s",
475 print_sensor(limit->type, limit->last_val),
476 print_sensor(limit->type, limit->lower));
477 break;
479 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO :
480 LOG_ALERT, "%s.%s%d: %s",
481 sdlim->dxname, sensor_type_s[limit->type],
482 limit->numt, us);
485 if (limit->command) {
486 int i = 0, n = 0, r;
487 char *cmd = limit->command;
488 char buf[BUFSIZ];
489 int len = sizeof(buf);
491 buf[0] = '\0';
492 for (i = n = 0; n < len; ++i) {
493 if (cmd[i] == '\0') {
494 buf[n++] = '\0';
495 break;
497 if (cmd[i] != '%') {
498 buf[n++] = limit->command[i];
499 continue;
501 i++;
502 if (cmd[i] == '\0') {
503 buf[n++] = '\0';
504 break;
507 switch (cmd[i]) {
508 case 'x':
509 r = snprintf(&buf[n], len - n, "%s",
510 sdlim->dxname);
511 break;
512 case 't':
513 r = snprintf(&buf[n], len - n, "%s",
514 sensor_type_s[limit->type]);
515 break;
516 case 'n':
517 r = snprintf(&buf[n], len - n, "%d",
518 limit->numt);
519 break;
520 case 'l':
522 char *s = "";
523 switch(limit->ustatus){
524 case SENSORSD_S_UNSPEC:
525 s = "uninitialised";
526 break;
527 case SENSORSD_S_INVALID:
528 s = "invalid";
529 break;
530 case SENSORSD_S_WITHIN:
531 s = "within";
532 break;
533 case SENSORSD_S_ABOVE:
534 s = "above";
535 break;
536 case SENSORSD_S_BELOW:
537 s = "below";
538 break;
540 r = snprintf(&buf[n], len - n, "%s",
542 break;
544 case 's':
546 char *s;
547 switch(limit->astatus){
548 case SENSOR_S_UNSPEC:
549 s = "UNSPEC";
550 break;
551 case SENSOR_S_OK:
552 s = "OK";
553 break;
554 case SENSOR_S_WARN:
555 s = "WARNING";
556 break;
557 case SENSOR_S_CRIT:
558 s = "CRITICAL";
559 break;
560 default:
561 s = "UNKNOWN";
563 r = snprintf(&buf[n], len - n, "%s",
565 break;
567 case '2':
568 r = snprintf(&buf[n], len - n, "%s",
569 print_sensor(limit->type,
570 limit->last_val));
571 break;
572 case '3':
573 r = snprintf(&buf[n], len - n, "%s",
574 print_sensor(limit->type,
575 limit->lower));
576 break;
577 case '4':
578 r = snprintf(&buf[n], len - n, "%s",
579 print_sensor(limit->type,
580 limit->upper));
581 break;
582 default:
583 r = snprintf(&buf[n], len - n, "%%%c",
584 cmd[i]);
585 break;
587 if (r < 0 || (r >= len - n)) {
588 syslog(LOG_CRIT, "could not parse "
589 "command");
590 return;
592 if (r > 0)
593 n += r;
595 if (buf[0])
596 execute(buf);
601 const char *drvstat[] = {
602 NULL, "empty", "ready", "powerup", "online", "idle", "active",
603 "rebuild", "powerdown", "fail", "pfail"
606 static char *
607 print_sensor(enum sensor_type type, int64_t value)
609 static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */
610 static int idx;
611 char *fbuf;
613 fbuf = rfbuf[idx++];
614 if (idx == RFBUFCNT)
615 idx = 0;
617 switch (type) {
618 case SENSOR_TEMP:
619 snprintf(fbuf, RFBUFSIZ, "%.2f degC",
620 (value - 273150000) / 1000000.0);
621 break;
622 case SENSOR_FANRPM:
623 snprintf(fbuf, RFBUFSIZ, "%lld RPM", value);
624 break;
625 case SENSOR_VOLTS_DC:
626 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0);
627 break;
628 case SENSOR_AMPS:
629 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0);
630 break;
631 case SENSOR_WATTHOUR:
632 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0);
633 break;
634 case SENSOR_AMPHOUR:
635 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0);
636 break;
637 case SENSOR_INDICATOR:
638 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off");
639 break;
640 case SENSOR_INTEGER:
641 snprintf(fbuf, RFBUFSIZ, "%lld", value);
642 break;
643 case SENSOR_PERCENT:
644 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0);
645 break;
646 case SENSOR_LUX:
647 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0);
648 break;
649 case SENSOR_DRIVE:
650 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0]))
651 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]);
652 else
653 snprintf(fbuf, RFBUFSIZ, "%lld ???", value);
654 break;
655 case SENSOR_TIMEDELTA:
656 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0);
657 break;
658 default:
659 snprintf(fbuf, RFBUFSIZ, "%lld ???", value);
662 return (fbuf);
665 void
666 parse_config(char *cf)
668 struct sdlim_t *sdlim;
670 TAILQ_FOREACH(sdlim, &sdlims, entries)
671 parse_config_sdlim(sdlim, cf);
674 void
675 parse_config_sdlim(struct sdlim_t *sdlim, char *cf)
677 struct limits_t *p;
678 char *buf = NULL, *ebuf = NULL;
679 char node[48];
680 char *cfa[2];
682 cfa[0] = cf;
683 cfa[1] = NULL;
685 TAILQ_FOREACH(p, &sdlim->limits, entries) {
686 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d",
687 sdlim->dxname, sensor_type_s[p->type], p->numt);
688 p->flags = 0;
689 if (cgetent(&buf, cfa, node) != 0)
690 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0)
691 continue;
692 if (cgetcap(buf, "istatus", ':'))
693 p->flags |= SENSORSD_L_ISTATUS;
694 if (cgetstr(buf, "low", &ebuf) < 0)
695 ebuf = NULL;
696 p->lower = get_val(ebuf, 0, p->type);
697 if (cgetstr(buf, "high", &ebuf) < 0)
698 ebuf = NULL;
699 p->upper = get_val(ebuf, 1, p->type);
700 if (cgetstr(buf, "command", &ebuf) < 0)
701 ebuf = NULL;
702 if (ebuf)
703 asprintf(&(p->command), "%s", ebuf);
704 free(buf);
705 buf = NULL;
706 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX)
707 p->flags |= SENSORSD_L_USERLIMIT;
711 int64_t
712 get_val(char *buf, int upper, enum sensor_type type)
714 double val;
715 int64_t rval = 0;
716 char *p;
718 if (buf == NULL) {
719 if (upper)
720 return (LLONG_MAX);
721 else
722 return (LLONG_MIN);
725 val = strtod(buf, &p);
726 if (buf == p)
727 err(1, "incorrect value: %s", buf);
729 switch(type) {
730 case SENSOR_TEMP:
731 switch(*p) {
732 case 'C':
733 printf("C");
734 rval = val * 1000 * 1000 + 273150000;
735 break;
736 case 'F':
737 printf("F");
738 rval = (val * 1000 * 1000 + 459670000) / 9 * 5;
739 break;
740 default:
741 errx(1, "unknown unit %s for temp sensor", p);
743 break;
744 case SENSOR_FANRPM:
745 rval = val;
746 break;
747 case SENSOR_VOLTS_DC:
748 if (*p != 'V')
749 errx(1, "unknown unit %s for voltage sensor", p);
750 rval = val * 1000 * 1000;
751 break;
752 case SENSOR_PERCENT:
753 rval = val * 1000.0;
754 break;
755 case SENSOR_INDICATOR:
756 case SENSOR_INTEGER:
757 case SENSOR_DRIVE:
758 rval = val;
759 break;
760 case SENSOR_AMPS:
761 case SENSOR_WATTHOUR:
762 case SENSOR_AMPHOUR:
763 case SENSOR_LUX:
764 rval = val * 1000 * 1000;
765 break;
766 case SENSOR_TIMEDELTA:
767 rval = val * 1000 * 1000 * 1000;
768 break;
769 default:
770 errx(1, "unsupported sensor type");
771 /* not reached */
773 free(buf);
774 return (rval);
777 /* ARGSUSED */
778 void
779 reparse_cfg(int signo)
781 reload = 1;