Bug Summary

File:src/usr.sbin/sensorsd/sensorsd.c
Warning:line 138, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sensorsd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/sensorsd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/sensorsd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/sensorsd/sensorsd.c
1/* $OpenBSD: sensorsd.c,v 1.68 2021/07/12 15:09:21 beck Exp $ */
2
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>
7 *
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.
11 *
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.
19 */
20
21#include <sys/types.h>
22#include <sys/sysctl.h>
23#include <sys/queue.h>
24#include <sys/time.h>
25#include <sys/sensors.h>
26
27#include <err.h>
28#include <errno(*__errno()).h>
29#include <signal.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <syslog.h>
34#include <time.h>
35#include <unistd.h>
36#include <limits.h>
37
38#define RFBUFSIZ28 28 /* buffer size for print_sensor */
39#define RFBUFCNT4 4 /* ring buffers */
40#define CHECK_PERIOD20 20 /* check every n seconds */
41
42enum sensorsd_s_status {
43 SENSORSD_S_UNSPEC, /* status is unspecified */
44 SENSORSD_S_INVALID, /* status is invalid, per SENSOR_FINVALID */
45 SENSORSD_S_WITHIN, /* status is within limits */
46 SENSORSD_S_ABOVE, /* status is above the higher limit */
47 SENSORSD_S_BELOW /* status is below the lower limit */
48};
49
50struct limits_t {
51 TAILQ_ENTRY(limits_t)struct { struct limits_t *tqe_next; struct limits_t **tqe_prev
; }
entries;
52 enum sensor_type type; /* sensor type */
53 int numt; /* sensor number */
54 int64_t last_val;
55 int64_t lower; /* lower limit */
56 int64_t upper; /* upper limit */
57 char *command; /* failure command */
58 time_t astatus_changed;
59 time_t ustatus_changed;
60 enum sensor_status astatus; /* last automatic status */
61 enum sensor_status astatus2;
62 enum sensorsd_s_status ustatus; /* last user-limit status */
63 enum sensorsd_s_status ustatus2;
64 int acount; /* stat change counter */
65 int ucount; /* stat change counter */
66 u_int8_t flags; /* sensorsd limit flags */
67#define SENSORSD_L_USERLIMIT0x0001 0x0001 /* user specified limit */
68#define SENSORSD_L_ISTATUS0x0002 0x0002 /* ignore automatic status */
69};
70
71struct sdlim_t {
72 TAILQ_ENTRY(sdlim_t)struct { struct sdlim_t *tqe_next; struct sdlim_t **tqe_prev;
}
entries;
73 char dxname[16]; /* device unix name */
74 int dev; /* device number */
75 int sensor_cnt;
76 TAILQ_HEAD(, limits_t)struct { struct limits_t *tqh_first; struct limits_t **tqh_last
; }
limits;
77};
78
79void usage(void);
80void create(void);
81struct sdlim_t *create_sdlim(struct sensordev *);
82void destroy_sdlim(struct sdlim_t *);
83void check(time_t);
84void check_sdlim(struct sdlim_t *, time_t);
85void execute(char *);
86void report(time_t);
87void report_sdlim(struct sdlim_t *, time_t);
88static char *print_sensor(enum sensor_type, int64_t);
89void parse_config(char *);
90void parse_config_sdlim(struct sdlim_t *, char *);
91int64_t get_val(char *, int, enum sensor_type);
92void reparse_cfg(int);
93
94TAILQ_HEAD(sdlimhead_t, sdlim_t)struct sdlimhead_t { struct sdlim_t *tqh_first; struct sdlim_t
**tqh_last; }
;
95struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims){ ((void *)0), &(sdlims).tqh_first };
96
97char *configfile, *configdb;
98volatile sig_atomic_t reload = 0;
99int debug = 0;
100
101void
102usage(void)
103{
104 extern char *__progname;
105 fprintf(stderr(&__sF[2]), "usage: %s [-d] [-c check] [-f file]\n",
106 __progname);
107 exit(1);
108}
109
110int
111main(int argc, char *argv[])
112{
113 time_t last_report = 0, this_check;
114 int ch, check_period = CHECK_PERIOD20;
115 const char *errstr;
116
117 while ((ch = getopt(argc, argv, "c:df:")) != -1) {
118 switch (ch) {
119 case 'c':
120 check_period = strtonum(optarg, 1, 600, &errstr);
121 if (errstr)
122 errx(1, "check %s", errstr);
123 break;
124 case 'd':
125 debug = 1;
126 break;
127 case 'f':
128 configfile = realpath(optarg, NULL((void *)0));
129 if (configfile == NULL((void *)0))
130 err(1, "configuration file %s", optarg);
131 break;
132 default:
133 usage();
134 }
135 }
136
137 argc -= optind;
138 argv += optind;
Value stored to 'argv' is never read
139 if (argc > 0)
140 usage();
141
142 if (configfile == NULL((void *)0))
143 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1)
144 err(1, "out of memory");
145 if (asprintf(&configdb, "%s.db", configfile) == -1)
146 err(1, "out of memory");
147
148 chdir("/");
149 if (unveil(configfile, "r") == -1)
150 err(1, "unveil %s", configfile);
151 if (unveil(configdb, "r") == -1)
152 err(1, "unveil %s", configdb);
153 if (unveil("/", "x") == -1)
154 err(1, "unveil /");
155
156 if (pledge("stdio rpath proc exec", NULL((void *)0)) == -1)
157 err(1, "pledge");
158
159 openlog("sensorsd", LOG_PID0x01 | LOG_NDELAY0x08, LOG_DAEMON(3<<3));
160
161 create();
162
163 parse_config(configfile);
164
165 if (debug == 0 && daemon(1, 0) == -1)
166 err(1, "unable to fork");
167
168 signal(SIGHUP1, reparse_cfg);
169 signal(SIGCHLD20, SIG_IGN(void (*)(int))1);
170
171 for (;;) {
172 if (reload) {
173 parse_config(configfile);
174 syslog(LOG_INFO6, "configuration reloaded");
175 reload = 0;
176 }
177 this_check = time(NULL((void *)0));
178 if (!(last_report < this_check))
179 this_check = last_report + 1;
180 check(this_check);
181 report(last_report);
182 last_report = this_check;
183 sleep(check_period);
184 }
185}
186
187void
188create(void)
189{
190 struct sensordev sensordev;
191 struct sdlim_t *sdlim;
192 size_t sdlen = sizeof(sensordev);
193 int mib[3], dev, sensor_cnt = 0;
194
195 mib[0] = CTL_HW6;
196 mib[1] = HW_SENSORS11;
197
198 for (dev = 0; ; dev++) {
199 mib[2] = dev;
200 if (sysctl(mib, 3, &sensordev, &sdlen, NULL((void *)0), 0) == -1) {
201 if (errno(*__errno()) == ENXIO6)
202 continue;
203 if (errno(*__errno()) == ENOENT2)
204 break;
205 warn("sysctl");
206 }
207 sdlim = create_sdlim(&sensordev);
208 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries)do { (sdlim)->entries.tqe_next = ((void *)0); (sdlim)->
entries.tqe_prev = (&sdlims)->tqh_last; *(&sdlims)
->tqh_last = (sdlim); (&sdlims)->tqh_last = &(sdlim
)->entries.tqe_next; } while (0)
;
209 sensor_cnt += sdlim->sensor_cnt;
210 }
211
212 syslog(LOG_INFO6, "startup, system has %d sensors", sensor_cnt);
213}
214
215struct sdlim_t *
216create_sdlim(struct sensordev *snsrdev)
217{
218 struct sensor sensor;
219 struct sdlim_t *sdlim;
220 struct limits_t *limit;
221 size_t slen = sizeof(sensor);
222 int mib[5], numt;
223 enum sensor_type type;
224
225 if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL((void *)0))
226 err(1, "calloc");
227
228 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname));
229
230 mib[0] = CTL_HW6;
231 mib[1] = HW_SENSORS11;
232 mib[2] = sdlim->dev = snsrdev->num;
233
234 TAILQ_INIT(&sdlim->limits)do { (&sdlim->limits)->tqh_first = ((void *)0); (&
sdlim->limits)->tqh_last = &(&sdlim->limits)
->tqh_first; } while (0)
;
235
236 for (type = 0; type < SENSOR_MAX_TYPES; type++) {
237 mib[3] = type;
238 for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
239 mib[4] = numt;
240 if (sysctl(mib, 5, &sensor, &slen, NULL((void *)0), 0) == -1) {
241 if (errno(*__errno()) != ENOENT2)
242 warn("sysctl");
243 continue;
244 }
245 if ((limit = calloc(1, sizeof(struct limits_t))) ==
246 NULL((void *)0))
247 err(1, "calloc");
248 limit->type = type;
249 limit->numt = numt;
250 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries)do { (limit)->entries.tqe_next = ((void *)0); (limit)->
entries.tqe_prev = (&sdlim->limits)->tqh_last; *(&
sdlim->limits)->tqh_last = (limit); (&sdlim->limits
)->tqh_last = &(limit)->entries.tqe_next; } while (
0)
;
251 sdlim->sensor_cnt++;
252 }
253 }
254
255 return (sdlim);
256}
257
258void
259destroy_sdlim(struct sdlim_t *sdlim)
260{
261 struct limits_t *limit;
262
263 while ((limit = TAILQ_FIRST(&sdlim->limits)((&sdlim->limits)->tqh_first)) != NULL((void *)0)) {
264 TAILQ_REMOVE(&sdlim->limits, limit, entries)do { if (((limit)->entries.tqe_next) != ((void *)0)) (limit
)->entries.tqe_next->entries.tqe_prev = (limit)->entries
.tqe_prev; else (&sdlim->limits)->tqh_last = (limit
)->entries.tqe_prev; *(limit)->entries.tqe_prev = (limit
)->entries.tqe_next; ; ; } while (0)
;
265 free(limit->command);
266 free(limit);
267 }
268 free(sdlim);
269}
270
271void
272check(time_t this_check)
273{
274 struct sensordev sensordev;
275 struct sdlim_t *sdlim, *next;
276 int mib[3];
277 int h, t, i;
278 size_t sdlen = sizeof(sensordev);
279
280 if (TAILQ_EMPTY(&sdlims)(((&sdlims)->tqh_first) == ((void *)0))) {
281 h = 0;
282 t = -1;
283 } else {
284 h = TAILQ_FIRST(&sdlims)((&sdlims)->tqh_first)->dev;
285 t = TAILQ_LAST(&sdlims, sdlimhead_t)(*(((struct sdlimhead_t *)((&sdlims)->tqh_last))->tqh_last
))
->dev;
286 }
287 sdlim = TAILQ_FIRST(&sdlims)((&sdlims)->tqh_first);
288
289 mib[0] = CTL_HW6;
290 mib[1] = HW_SENSORS11;
291 /* look ahead for 4 more sensordevs */
292 for (i = h; i <= t + 4; i++) {
293 if (sdlim != NULL((void *)0) && i > sdlim->dev)
294 sdlim = TAILQ_NEXT(sdlim, entries)((sdlim)->entries.tqe_next);
295 if (sdlim == NULL((void *)0) && i <= t)
296 syslog(LOG_ALERT1, "inconsistent sdlim logic");
297 mib[2] = i;
298 if (sysctl(mib, 3, &sensordev, &sdlen, NULL((void *)0), 0) == -1) {
299 if (errno(*__errno()) != ENOENT2)
300 warn("sysctl");
301 if (sdlim != NULL((void *)0) && i == sdlim->dev) {
302 next = TAILQ_NEXT(sdlim, entries)((sdlim)->entries.tqe_next);
303 TAILQ_REMOVE(&sdlims, sdlim, entries)do { if (((sdlim)->entries.tqe_next) != ((void *)0)) (sdlim
)->entries.tqe_next->entries.tqe_prev = (sdlim)->entries
.tqe_prev; else (&sdlims)->tqh_last = (sdlim)->entries
.tqe_prev; *(sdlim)->entries.tqe_prev = (sdlim)->entries
.tqe_next; ; ; } while (0)
;
304 syslog(LOG_INFO6, "%s has disappeared",
305 sdlim->dxname);
306 destroy_sdlim(sdlim);
307 sdlim = next;
308 }
309 continue;
310 }
311 if (sdlim != NULL((void *)0) && i == sdlim->dev) {
312 if (strcmp(sdlim->dxname, sensordev.xname) == 0) {
313 check_sdlim(sdlim, this_check);
314 continue;
315 } else {
316 next = TAILQ_NEXT(sdlim, entries)((sdlim)->entries.tqe_next);
317 TAILQ_REMOVE(&sdlims, sdlim, entries)do { if (((sdlim)->entries.tqe_next) != ((void *)0)) (sdlim
)->entries.tqe_next->entries.tqe_prev = (sdlim)->entries
.tqe_prev; else (&sdlims)->tqh_last = (sdlim)->entries
.tqe_prev; *(sdlim)->entries.tqe_prev = (sdlim)->entries
.tqe_next; ; ; } while (0)
;
318 syslog(LOG_INFO6, "%s has been replaced",
319 sdlim->dxname);
320 destroy_sdlim(sdlim);
321 sdlim = next;
322 }
323 }
324 next = create_sdlim(&sensordev);
325 /* inserting next before sdlim */
326 if (sdlim != NULL((void *)0))
327 TAILQ_INSERT_BEFORE(sdlim, next, entries)do { (next)->entries.tqe_prev = (sdlim)->entries.tqe_prev
; (next)->entries.tqe_next = (sdlim); *(sdlim)->entries
.tqe_prev = (next); (sdlim)->entries.tqe_prev = &(next
)->entries.tqe_next; } while (0)
;
328 else
329 TAILQ_INSERT_TAIL(&sdlims, next, entries)do { (next)->entries.tqe_next = ((void *)0); (next)->entries
.tqe_prev = (&sdlims)->tqh_last; *(&sdlims)->tqh_last
= (next); (&sdlims)->tqh_last = &(next)->entries
.tqe_next; } while (0)
;
330 syslog(LOG_INFO6, "%s has appeared", next->dxname);
331 sdlim = next;
332 parse_config_sdlim(sdlim, configfile);
333 check_sdlim(sdlim, this_check);
334 }
335
336 if (TAILQ_EMPTY(&sdlims)(((&sdlims)->tqh_first) == ((void *)0)))
337 return;
338 /* Ensure that our queue is consistent. */
339 for (sdlim = TAILQ_FIRST(&sdlims)((&sdlims)->tqh_first);
340 (next = TAILQ_NEXT(sdlim, entries)((sdlim)->entries.tqe_next)) != NULL((void *)0);
341 sdlim = next)
342 if (sdlim->dev > next->dev)
343 syslog(LOG_ALERT1, "inconsistent sdlims queue");
344}
345
346void
347check_sdlim(struct sdlim_t *sdlim, time_t this_check)
348{
349 struct sensor sensor;
350 struct limits_t *limit;
351 size_t len;
352 int mib[5];
353
354 mib[0] = CTL_HW6;
355 mib[1] = HW_SENSORS11;
356 mib[2] = sdlim->dev;
357 len = sizeof(sensor);
358
359 TAILQ_FOREACH(limit, &sdlim->limits, entries)for((limit) = ((&sdlim->limits)->tqh_first); (limit
) != ((void *)0); (limit) = ((limit)->entries.tqe_next))
{
360 if ((limit->flags & SENSORSD_L_ISTATUS0x0002) &&
361 !(limit->flags & SENSORSD_L_USERLIMIT0x0001))
362 continue;
363
364 mib[3] = limit->type;
365 mib[4] = limit->numt;
366 if (sysctl(mib, 5, &sensor, &len, NULL((void *)0), 0) == -1)
367 err(1, "sysctl");
368
369 if (!(limit->flags & SENSORSD_L_ISTATUS0x0002)) {
370 enum sensor_status newastatus = sensor.status;
371
372 if (limit->astatus != newastatus) {
373 if (limit->astatus2 != newastatus) {
374 limit->astatus2 = newastatus;
375 limit->acount = 0;
376 } else if (++limit->acount >= 3) {
377 limit->last_val = sensor.value;
378 limit->astatus2 =
379 limit->astatus = newastatus;
380 limit->astatus_changed = this_check;
381 }
382 }
383 }
384
385 if (limit->flags & SENSORSD_L_USERLIMIT0x0001) {
386 enum sensorsd_s_status newustatus;
387
388 if (sensor.flags & SENSOR_FINVALID0x0001)
389 newustatus = SENSORSD_S_INVALID;
390 else if (sensor.value > limit->upper)
391 newustatus = SENSORSD_S_ABOVE;
392 else if (sensor.value < limit->lower)
393 newustatus = SENSORSD_S_BELOW;
394 else
395 newustatus = SENSORSD_S_WITHIN;
396
397 if (limit->ustatus != newustatus) {
398 if (limit->ustatus2 != newustatus) {
399 limit->ustatus2 = newustatus;
400 limit->ucount = 0;
401 } else if (++limit->ucount >= 3) {
402 limit->last_val = sensor.value;
403 limit->ustatus2 =
404 limit->ustatus = newustatus;
405 limit->ustatus_changed = this_check;
406 }
407 }
408 }
409 }
410}
411
412void
413execute(char *command)
414{
415 char *argp[] = {"sh", "-c", command, NULL((void *)0)};
416
417 switch (fork()) {
418 case -1:
419 syslog(LOG_CRIT2, "execute: fork() failed");
420 break;
421 case 0:
422 execv("/bin/sh", argp);
423 _exit(1);
424 /* NOTREACHED */
425 default:
426 break;
427 }
428}
429
430void
431report(time_t last_report)
432{
433 struct sdlim_t *sdlim;
434
435 TAILQ_FOREACH(sdlim, &sdlims, entries)for((sdlim) = ((&sdlims)->tqh_first); (sdlim) != ((void
*)0); (sdlim) = ((sdlim)->entries.tqe_next))
436 report_sdlim(sdlim, last_report);
437}
438
439void
440report_sdlim(struct sdlim_t *sdlim, time_t last_report)
441{
442 struct limits_t *limit;
443
444 TAILQ_FOREACH(limit, &sdlim->limits, entries)for((limit) = ((&sdlim->limits)->tqh_first); (limit
) != ((void *)0); (limit) = ((limit)->entries.tqe_next))
{
445 if ((limit->astatus_changed <= last_report) &&
446 (limit->ustatus_changed <= last_report))
447 continue;
448
449 if (limit->astatus_changed > last_report) {
450 const char *as = NULL((void *)0);
451
452 switch (limit->astatus) {
453 case SENSOR_S_UNSPEC:
454 as = "";
455 break;
456 case SENSOR_S_OK:
457 as = ", OK";
458 break;
459 case SENSOR_S_WARN:
460 as = ", WARN";
461 break;
462 case SENSOR_S_CRIT:
463 as = ", CRITICAL";
464 break;
465 case SENSOR_S_UNKNOWN:
466 as = ", UNKNOWN";
467 break;
468 }
469 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO6 :
470 LOG_ALERT1, "%s.%s%d: %s%s",
471 sdlim->dxname, sensor_type_s[limit->type],
472 limit->numt,
473 print_sensor(limit->type, limit->last_val), as);
474 }
475
476 if (limit->ustatus_changed > last_report) {
477 char us[BUFSIZ1024];
478
479 switch (limit->ustatus) {
480 case SENSORSD_S_UNSPEC:
481 snprintf(us, sizeof(us),
482 "ustatus uninitialised");
483 break;
484 case SENSORSD_S_INVALID:
485 snprintf(us, sizeof(us), "marked invalid");
486 break;
487 case SENSORSD_S_WITHIN:
488 snprintf(us, sizeof(us),
489 "within limits: %s",
490 print_sensor(limit->type, limit->last_val));
491 break;
492 case SENSORSD_S_ABOVE:
493 snprintf(us, sizeof(us),
494 "exceeds limits: %s is above %s",
495 print_sensor(limit->type, limit->last_val),
496 print_sensor(limit->type, limit->upper));
497 break;
498 case SENSORSD_S_BELOW:
499 snprintf(us, sizeof(us),
500 "exceeds limits: %s is below %s",
501 print_sensor(limit->type, limit->last_val),
502 print_sensor(limit->type, limit->lower));
503 break;
504 }
505 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO6 :
506 LOG_ALERT1, "%s.%s%d: %s",
507 sdlim->dxname, sensor_type_s[limit->type],
508 limit->numt, us);
509 }
510
511 if (limit->command) {
512 int i = 0, n = 0, r;
513 char *cmd = limit->command;
514 char buf[BUFSIZ1024];
515 int len = sizeof(buf);
516
517 buf[0] = '\0';
518 for (i = n = 0; n < len; ++i) {
519 if (cmd[i] == '\0') {
520 buf[n++] = '\0';
521 break;
522 }
523 if (cmd[i] != '%') {
524 buf[n++] = limit->command[i];
525 continue;
526 }
527 i++;
528 if (cmd[i] == '\0') {
529 buf[n++] = '\0';
530 break;
531 }
532
533 switch (cmd[i]) {
534 case 'x':
535 r = snprintf(&buf[n], len - n, "%s",
536 sdlim->dxname);
537 break;
538 case 't':
539 r = snprintf(&buf[n], len - n, "%s",
540 sensor_type_s[limit->type]);
541 break;
542 case 'n':
543 r = snprintf(&buf[n], len - n, "%d",
544 limit->numt);
545 break;
546 case 'l':
547 {
548 char *s = "";
549 switch (limit->ustatus) {
550 case SENSORSD_S_UNSPEC:
551 s = "uninitialised";
552 break;
553 case SENSORSD_S_INVALID:
554 s = "invalid";
555 break;
556 case SENSORSD_S_WITHIN:
557 s = "within";
558 break;
559 case SENSORSD_S_ABOVE:
560 s = "above";
561 break;
562 case SENSORSD_S_BELOW:
563 s = "below";
564 break;
565 }
566 r = snprintf(&buf[n], len - n, "%s",
567 s);
568 break;
569 }
570 case 's':
571 {
572 char *s;
573 switch (limit->astatus) {
574 case SENSOR_S_UNSPEC:
575 s = "UNSPEC";
576 break;
577 case SENSOR_S_OK:
578 s = "OK";
579 break;
580 case SENSOR_S_WARN:
581 s = "WARNING";
582 break;
583 case SENSOR_S_CRIT:
584 s = "CRITICAL";
585 break;
586 default:
587 s = "UNKNOWN";
588 }
589 r = snprintf(&buf[n], len - n, "%s",
590 s);
591 break;
592 }
593 case '2':
594 r = snprintf(&buf[n], len - n, "%s",
595 print_sensor(limit->type,
596 limit->last_val));
597 break;
598 case '3':
599 r = snprintf(&buf[n], len - n, "%s",
600 print_sensor(limit->type,
601 limit->lower));
602 break;
603 case '4':
604 r = snprintf(&buf[n], len - n, "%s",
605 print_sensor(limit->type,
606 limit->upper));
607 break;
608 default:
609 r = snprintf(&buf[n], len - n, "%%%c",
610 cmd[i]);
611 break;
612 }
613 if (r == -1 || (r >= len - n)) {
614 syslog(LOG_CRIT2, "could not parse "
615 "command");
616 return;
617 }
618 if (r > 0)
619 n += r;
620 }
621 if (buf[0])
622 execute(buf);
623 }
624 }
625}
626
627const char *drvstat[] = {
628 NULL((void *)0), "empty", "ready", "powerup", "online", "idle", "active",
629 "rebuild", "powerdown", "fail", "pfail"
630};
631
632static char *
633print_sensor(enum sensor_type type, int64_t value)
634{
635 static char rfbuf[RFBUFCNT4][RFBUFSIZ28]; /* ring buffer */
636 static int idx;
637 char *fbuf;
638
639 fbuf = rfbuf[idx++];
640 if (idx == RFBUFCNT4)
641 idx = 0;
642
643 switch (type) {
644 case SENSOR_TEMP:
645 snprintf(fbuf, RFBUFSIZ28, "%.2f degC",
646 (value - 273150000) / 1000000.0);
647 break;
648 case SENSOR_FANRPM:
649 snprintf(fbuf, RFBUFSIZ28, "%lld RPM", value);
650 break;
651 case SENSOR_VOLTS_DC:
652 snprintf(fbuf, RFBUFSIZ28, "%.2f V DC", value / 1000000.0);
653 break;
654 case SENSOR_VOLTS_AC:
655 snprintf(fbuf, RFBUFSIZ28, "%.2f V AC", value / 1000000.0);
656 break;
657 case SENSOR_WATTS:
658 snprintf(fbuf, RFBUFSIZ28, "%.2f W", value / 1000000.0);
659 break;
660 case SENSOR_AMPS:
661 snprintf(fbuf, RFBUFSIZ28, "%.2f A", value / 1000000.0);
662 break;
663 case SENSOR_WATTHOUR:
664 snprintf(fbuf, RFBUFSIZ28, "%.2f Wh", value / 1000000.0);
665 break;
666 case SENSOR_AMPHOUR:
667 snprintf(fbuf, RFBUFSIZ28, "%.2f Ah", value / 1000000.0);
668 break;
669 case SENSOR_INDICATOR:
670 snprintf(fbuf, RFBUFSIZ28, "%s", value? "On" : "Off");
671 break;
672 case SENSOR_INTEGER:
673 snprintf(fbuf, RFBUFSIZ28, "%lld", value);
674 break;
675 case SENSOR_PERCENT:
676 snprintf(fbuf, RFBUFSIZ28, "%.2f%%", value / 1000.0);
677 break;
678 case SENSOR_LUX:
679 snprintf(fbuf, RFBUFSIZ28, "%.2f lx", value / 1000000.0);
680 break;
681 case SENSOR_DRIVE:
682 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0]))
683 snprintf(fbuf, RFBUFSIZ28, "%s", drvstat[value]);
684 else
685 snprintf(fbuf, RFBUFSIZ28, "%lld ???", value);
686 break;
687 case SENSOR_TIMEDELTA:
688 snprintf(fbuf, RFBUFSIZ28, "%.6f secs", value / 1000000000.0);
689 break;
690 case SENSOR_HUMIDITY:
691 snprintf(fbuf, RFBUFSIZ28, "%.2f%%", value / 1000.0);
692 break;
693 case SENSOR_FREQ:
694 snprintf(fbuf, RFBUFSIZ28, "%.2f Hz", value / 1000000.0);
695 break;
696 case SENSOR_ANGLE:
697 snprintf(fbuf, RFBUFSIZ28, "%lld", value);
698 break;
699 case SENSOR_DISTANCE:
700 snprintf(fbuf, RFBUFSIZ28, "%.3f m", value / 1000000.0);
701 break;
702 case SENSOR_PRESSURE:
703 snprintf(fbuf, RFBUFSIZ28, "%.2f Pa", value / 1000.0);
704 break;
705 case SENSOR_ACCEL:
706 snprintf(fbuf, RFBUFSIZ28, "%2.4f m/s^2", value / 1000000.0);
707 break;
708 case SENSOR_VELOCITY:
709 snprintf(fbuf, RFBUFSIZ28, "%4.3f m/s", value / 1000000.0);
710 break;
711 default:
712 snprintf(fbuf, RFBUFSIZ28, "%lld ???", value);
713 }
714
715 return (fbuf);
716}
717
718void
719parse_config(char *cf)
720{
721 struct sdlim_t *sdlim;
722
723 TAILQ_FOREACH(sdlim, &sdlims, entries)for((sdlim) = ((&sdlims)->tqh_first); (sdlim) != ((void
*)0); (sdlim) = ((sdlim)->entries.tqe_next))
724 parse_config_sdlim(sdlim, cf);
725}
726
727void
728parse_config_sdlim(struct sdlim_t *sdlim, char *cf)
729{
730 struct limits_t *p;
731 char *buf = NULL((void *)0), *ebuf = NULL((void *)0);
732 char node[48];
733 char *cfa[2];
734
735 cfa[0] = cf;
736 cfa[1] = NULL((void *)0);
737
738 TAILQ_FOREACH(p, &sdlim->limits, entries)for((p) = ((&sdlim->limits)->tqh_first); (p) != ((void
*)0); (p) = ((p)->entries.tqe_next))
{
739 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d",
740 sdlim->dxname, sensor_type_s[p->type], p->numt);
741 p->flags = 0;
742 if (cgetent(&buf, cfa, node) != 0)
743 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0)
744 continue;
745 if (cgetcap(buf, "istatus", ':'))
746 p->flags |= SENSORSD_L_ISTATUS0x0002;
747 if (cgetstr(buf, "low", &ebuf) < 0)
748 ebuf = NULL((void *)0);
749 p->lower = get_val(ebuf, 0, p->type);
750 if (cgetstr(buf, "high", &ebuf) < 0)
751 ebuf = NULL((void *)0);
752 p->upper = get_val(ebuf, 1, p->type);
753 if (cgetstr(buf, "command", &ebuf) < 0)
754 ebuf = NULL((void *)0);
755 if (ebuf != NULL((void *)0)) {
756 p->command = ebuf;
757 ebuf = NULL((void *)0);
758 }
759 free(buf);
760 buf = NULL((void *)0);
761 if (p->lower != LLONG_MIN(-9223372036854775807LL -1LL) || p->upper != LLONG_MAX9223372036854775807LL)
762 p->flags |= SENSORSD_L_USERLIMIT0x0001;
763 }
764}
765
766int64_t
767get_val(char *buf, int upper, enum sensor_type type)
768{
769 double val;
770 int64_t rval = 0;
771 char *p;
772
773 if (buf == NULL((void *)0)) {
774 if (upper)
775 return (LLONG_MAX9223372036854775807LL);
776 else
777 return (LLONG_MIN(-9223372036854775807LL -1LL));
778 }
779
780 val = strtod(buf, &p);
781 if (buf == p)
782 err(1, "incorrect value: %s", buf);
783
784 switch (type) {
785 case SENSOR_TEMP:
786 switch (*p) {
787 case 'C':
788 printf("C");
789 rval = val * 1000 * 1000 + 273150000;
790 break;
791 case 'F':
792 printf("F");
793 rval = (val * 1000 * 1000 + 459670000) / 9 * 5;
794 break;
795 default:
796 errx(1, "unknown unit %s for temp sensor", p);
797 }
798 break;
799 case SENSOR_FANRPM:
800 rval = val;
801 break;
802 case SENSOR_VOLTS_DC:
803 case SENSOR_VOLTS_AC:
804 if (*p != 'V')
805 errx(1, "unknown unit %s for voltage sensor", p);
806 rval = val * 1000 * 1000;
807 break;
808 case SENSOR_PERCENT:
809 rval = val * 1000.0;
810 break;
811 case SENSOR_INDICATOR:
812 case SENSOR_INTEGER:
813 case SENSOR_DRIVE:
814 case SENSOR_ANGLE:
815 rval = val;
816 break;
817 case SENSOR_WATTS:
818 case SENSOR_AMPS:
819 case SENSOR_WATTHOUR:
820 case SENSOR_AMPHOUR:
821 case SENSOR_LUX:
822 case SENSOR_FREQ:
823 case SENSOR_ACCEL:
824 case SENSOR_DISTANCE:
825 case SENSOR_VELOCITY:
826 rval = val * 1000 * 1000;
827 break;
828 case SENSOR_TIMEDELTA:
829 rval = val * 1000 * 1000 * 1000;
830 break;
831 case SENSOR_HUMIDITY:
832 case SENSOR_PRESSURE:
833 rval = val * 1000.0;
834 break;
835 default:
836 errx(1, "unsupported sensor type");
837 /* not reached */
838 }
839 free(buf);
840 return (rval);
841}
842
843/* ARGSUSED */
844void
845reparse_cfg(int signo)
846{
847 reload = 1;
848}