Merge branch 'vendor/BINUTILS_ALL'
[dragonfly.git] / usr.sbin / sensorsd / sensorsd.c
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 $ */
3
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>
8  *
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.
12  *
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.
20  */
21
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
24 #include <sys/sensors.h>
25
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>
35
36 #define RFBUFSIZ        28      /* buffer size for print_sensor */
37 #define RFBUFCNT        4       /* ring buffers */
38 #define CHECK_PERIOD    20      /* check every n seconds */
39
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 */
46 };
47
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 */
67 };
68
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;
75 };
76
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);
91
92 TAILQ_HEAD(sdlimhead_t, sdlim_t);
93 struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims);
94
95 char                     *configfile;
96 volatile sig_atomic_t     reload = 0;
97 int                       debug = 0;
98
99 void
100 usage(void)
101 {
102         extern char *__progname;
103         fprintf(stderr, "usage: %s [-d] [-c check]\n", __progname);
104         exit(1);
105 }
106
107 int
108 main(int argc, char *argv[])
109 {
110         time_t           last_report = 0, this_check;
111         int              ch, check_period = CHECK_PERIOD;
112         const char      *errstr;
113
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();
126                 }
127         }
128
129         argc -= optind;
130         argv += optind;
131         if (argc > 0)
132                 usage();
133
134         openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
135
136         create();
137
138         if (configfile == NULL)
139                 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1)
140                         err(1, "out of memory");
141         parse_config(configfile);
142
143         if (debug == 0 && daemon(0, 0) == -1)
144                 err(1, "unable to fork");
145
146         signal(SIGHUP, reparse_cfg);
147         signal(SIGCHLD, SIG_IGN);
148
149         for (;;) {
150                 if (reload) {
151                         parse_config(configfile);
152                         syslog(LOG_INFO, "configuration reloaded");
153                         reload = 0;
154                 }
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);
162         }
163 }
164
165 void
166 create(void)
167 {
168         struct sensordev sensordev;
169         struct sdlim_t  *sdlim;
170         size_t           sdlen = sizeof(sensordev);
171         int              mib[3], dev, sensor_cnt = 0;
172
173         mib[0] = CTL_HW;
174         mib[1] = HW_SENSORS;
175
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;
182                 }
183                 sdlim = create_sdlim(&sensordev);
184                 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries);
185                 sensor_cnt += sdlim->sensor_cnt;
186         }
187
188         syslog(LOG_INFO, "startup, system has %d sensors", sensor_cnt);
189 }
190
191 struct sdlim_t *
192 create_sdlim(struct sensordev *snsrdev)
193 {
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;
200
201         if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL)
202                 err(1, "calloc");
203
204         strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname));
205
206         mib[0] = CTL_HW;
207         mib[1] = HW_SENSORS;
208         mib[2] = sdlim->dev = snsrdev->num;
209
210         TAILQ_INIT(&sdlim->limits);
211
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;
220                         }
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++;
228                 }
229         }
230
231         return (sdlim);
232 }
233
234 void
235 destroy_sdlim(struct sdlim_t *sdlim)
236 {
237         struct limits_t         *limit;
238
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);
244         }
245         free(sdlim);
246 }
247
248 void
249 check(time_t this_check)
250 {
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);
256
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;
263         }
264         sdlim = TAILQ_FIRST(&sdlims);
265
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;
285                         }
286                         continue;
287                 }
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;
299                         }
300                 }
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);
311         }
312
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");
321 }
322
323 void
324 check_sdlim(struct sdlim_t *sdlim, time_t this_check)
325 {
326         struct sensor            sensor;
327         struct limits_t         *limit;
328         size_t                   len;
329         int                      mib[5];
330
331         mib[0] = CTL_HW;
332         mib[1] = HW_SENSORS;
333         mib[2] = sdlim->dev;
334         len = sizeof(sensor);
335
336         TAILQ_FOREACH(limit, &sdlim->limits, entries) {
337                 if ((limit->flags & SENSORSD_L_ISTATUS) &&
338                     !(limit->flags & SENSORSD_L_USERLIMIT))
339                         continue;
340
341                 mib[3] = limit->type;
342                 mib[4] = limit->numt;
343                 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1)
344                         err(1, "sysctl");
345
346                 if (!(limit->flags & SENSORSD_L_ISTATUS)) {
347                         enum sensor_status      newastatus = sensor.status;
348
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;
358                                 }
359                         }
360                 }
361
362                 if (limit->flags & SENSORSD_L_USERLIMIT) {
363                         enum sensorsd_s_status   newustatus;
364
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;
373
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;
383                                 }
384                         }
385                 }
386         }
387 }
388
389 void
390 execute(char *command)
391 {
392         char *argp[] = {"sh", "-c", command, NULL};
393
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;
404         }
405 }
406
407 void
408 report(time_t last_report)
409 {
410         struct sdlim_t  *sdlim;
411
412         TAILQ_FOREACH(sdlim, &sdlims, entries)
413                 report_sdlim(sdlim, last_report);
414 }
415
416 void
417 report_sdlim(struct sdlim_t *sdlim, time_t last_report)
418 {
419         struct limits_t *limit;
420
421         TAILQ_FOREACH(limit, &sdlim->limits, entries) {
422                 if ((limit->astatus_changed <= last_report) &&
423                     (limit->ustatus_changed <= last_report))
424                         continue;
425
426                 if (limit->astatus_changed > last_report) {
427                         const char *as = NULL;
428
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;
445                         }
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);
451                 }
452
453                 if (limit->ustatus_changed > last_report) {
454                         char us[BUFSIZ];
455
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;
478                         }
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);
483                 }
484
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);
490
491                         buf[0] = '\0';
492                         for (i = n = 0; n < len; ++i) {
493                                 if (cmd[i] == '\0') {
494                                         buf[n++] = '\0';
495                                         break;
496                                 }
497                                 if (cmd[i] != '%') {
498                                         buf[n++] = limit->command[i];
499                                         continue;
500                                 }
501                                 i++;
502                                 if (cmd[i] == '\0') {
503                                         buf[n++] = '\0';
504                                         break;
505                                 }
506
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':
521                                 {
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;
539                                         }
540                                         r = snprintf(&buf[n], len - n, "%s",
541                                             s);
542                                         break;
543                                 }
544                                 case 's':
545                                 {
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";
562                                         }
563                                         r = snprintf(&buf[n], len - n, "%s",
564                                             s);
565                                         break;
566                                 }
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;
586                                 }
587                                 if (r < 0 || (r >= len - n)) {
588                                         syslog(LOG_CRIT, "could not parse "
589                                             "command");
590                                         return;
591                                 }
592                                 if (r > 0)
593                                         n += r;
594                         }
595                         if (buf[0])
596                                 execute(buf);
597                 }
598         }
599 }
600
601 const char *drvstat[] = {
602         NULL, "empty", "ready", "powerup", "online", "idle", "active",
603         "rebuild", "powerdown", "fail", "pfail"
604 };
605
606 static char *
607 print_sensor(enum sensor_type type, int64_t value)
608 {
609         static char      rfbuf[RFBUFCNT][RFBUFSIZ];     /* ring buffer */
610         static int       idx;
611         char            *fbuf;
612
613         fbuf = rfbuf[idx++];
614         if (idx == RFBUFCNT)
615                 idx = 0;
616
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);
660         }
661
662         return (fbuf);
663 }
664
665 void
666 parse_config(char *cf)
667 {
668         struct sdlim_t   *sdlim;
669
670         TAILQ_FOREACH(sdlim, &sdlims, entries)
671                 parse_config_sdlim(sdlim, cf);
672 }
673
674 void
675 parse_config_sdlim(struct sdlim_t *sdlim, char *cf)
676 {
677         struct limits_t  *p;
678         char             *buf = NULL, *ebuf = NULL;
679         char              node[48];
680         char             *cfa[2];
681         
682         cfa[0] = cf;
683         cfa[1] = NULL;
684
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;
708         }
709 }
710
711 int64_t
712 get_val(char *buf, int upper, enum sensor_type type)
713 {
714         double   val;
715         int64_t  rval = 0;
716         char    *p;
717
718         if (buf == NULL) {
719                 if (upper)
720                         return (LLONG_MAX);
721                 else
722                         return (LLONG_MIN);
723         }
724
725         val = strtod(buf, &p);
726         if (buf == p)
727                 err(1, "incorrect value: %s", buf);
728
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);
742                 }
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 */
772         }
773         free(buf);
774         return (rval);
775 }
776
777 /* ARGSUSED */
778 void
779 reparse_cfg(int signo)
780 {
781         reload = 1;
782 }