File: | src/usr.sbin/sensorsd/sensorsd.c |
Warning: | line 138, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
42 | enum 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 | |
50 | struct 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 | |
71 | struct 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 | |
79 | void usage(void); |
80 | void create(void); |
81 | struct sdlim_t *create_sdlim(struct sensordev *); |
82 | void destroy_sdlim(struct sdlim_t *); |
83 | void check(time_t); |
84 | void check_sdlim(struct sdlim_t *, time_t); |
85 | void execute(char *); |
86 | void report(time_t); |
87 | void report_sdlim(struct sdlim_t *, time_t); |
88 | static char *print_sensor(enum sensor_type, int64_t); |
89 | void parse_config(char *); |
90 | void parse_config_sdlim(struct sdlim_t *, char *); |
91 | int64_t get_val(char *, int, enum sensor_type); |
92 | void reparse_cfg(int); |
93 | |
94 | TAILQ_HEAD(sdlimhead_t, sdlim_t)struct sdlimhead_t { struct sdlim_t *tqh_first; struct sdlim_t **tqh_last; }; |
95 | struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims){ ((void *)0), &(sdlims).tqh_first }; |
96 | |
97 | char *configfile, *configdb; |
98 | volatile sig_atomic_t reload = 0; |
99 | int debug = 0; |
100 | |
101 | void |
102 | usage(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 | |
110 | int |
111 | main(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 | |
187 | void |
188 | create(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 | |
215 | struct sdlim_t * |
216 | create_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 | |
258 | void |
259 | destroy_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 | |
271 | void |
272 | check(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 | |
346 | void |
347 | check_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 | |
412 | void |
413 | execute(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 | |
430 | void |
431 | report(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 | |
439 | void |
440 | report_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 | |
627 | const char *drvstat[] = { |
628 | NULL((void *)0), "empty", "ready", "powerup", "online", "idle", "active", |
629 | "rebuild", "powerdown", "fail", "pfail" |
630 | }; |
631 | |
632 | static char * |
633 | print_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 | |
718 | void |
719 | parse_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 | |
727 | void |
728 | parse_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 | |
766 | int64_t |
767 | get_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 */ |
844 | void |
845 | reparse_cfg(int signo) |
846 | { |
847 | reload = 1; |
848 | } |