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.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 RFBUFSIZ 28 /* buffer size for print_sensor */ 39 #define RFBUFCNT 4 /* ring buffers */ 40 #define CHECK_PERIOD 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) 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_USERLIMIT 0x0001 /* user specified limit */ 68 #define SENSORSD_L_ISTATUS 0x0002 /* ignore automatic status */ 69 }; 70 71 struct sdlim_t { 72 TAILQ_ENTRY(sdlim_t) entries; 73 char dxname[16]; /* device unix name */ 74 int dev; /* device number */ 75 int sensor_cnt; 76 TAILQ_HEAD(, limits_t) 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); 95 struct sdlimhead_t sdlims = TAILQ_HEAD_INITIALIZER(sdlims); 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, "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_PERIOD; 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); 129 if (configfile == NULL) 130 err(1, "configuration file %s", optarg); 131 break; 132 default: 133 usage(); 134 } 135 } 136 137 argc -= optind; 138 argv += optind; 139 if (argc > 0) 140 usage(); 141 142 if (configfile == NULL) 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) == -1) 157 err(1, "pledge"); 158 159 openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 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(SIGHUP, reparse_cfg); 169 signal(SIGCHLD, SIG_IGN); 170 171 for (;;) { 172 if (reload) { 173 parse_config(configfile); 174 syslog(LOG_INFO, "configuration reloaded"); 175 reload = 0; 176 } 177 this_check = time(NULL); 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_HW; 196 mib[1] = HW_SENSORS; 197 198 for (dev = 0; ; dev++) { 199 mib[2] = dev; 200 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 201 if (errno == ENXIO) 202 continue; 203 if (errno == ENOENT) 204 break; 205 warn("sysctl"); 206 } 207 sdlim = create_sdlim(&sensordev); 208 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries); 209 sensor_cnt += sdlim->sensor_cnt; 210 } 211 212 syslog(LOG_INFO, "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) 226 err(1, "calloc"); 227 228 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname)); 229 230 mib[0] = CTL_HW; 231 mib[1] = HW_SENSORS; 232 mib[2] = sdlim->dev = snsrdev->num; 233 234 TAILQ_INIT(&sdlim->limits); 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, 0) == -1) { 241 if (errno != ENOENT) 242 warn("sysctl"); 243 continue; 244 } 245 if ((limit = calloc(1, sizeof(struct limits_t))) == 246 NULL) 247 err(1, "calloc"); 248 limit->type = type; 249 limit->numt = numt; 250 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries); 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)) != NULL) { 264 TAILQ_REMOVE(&sdlim->limits, limit, entries); 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)) { 281 h = 0; 282 t = -1; 283 } else { 284 h = TAILQ_FIRST(&sdlims)->dev; 285 t = TAILQ_LAST(&sdlims, sdlimhead_t)->dev; 286 } 287 sdlim = TAILQ_FIRST(&sdlims); 288 289 mib[0] = CTL_HW; 290 mib[1] = HW_SENSORS; 291 /* look ahead for 4 more sensordevs */ 292 for (i = h; i <= t + 4; i++) { 293 if (sdlim != NULL && i > sdlim->dev) 294 sdlim = TAILQ_NEXT(sdlim, entries); 295 if (sdlim == NULL && i <= t) 296 syslog(LOG_ALERT, "inconsistent sdlim logic"); 297 mib[2] = i; 298 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 299 if (errno != ENOENT) 300 warn("sysctl"); 301 if (sdlim != NULL && i == sdlim->dev) { 302 next = TAILQ_NEXT(sdlim, entries); 303 TAILQ_REMOVE(&sdlims, sdlim, entries); 304 syslog(LOG_INFO, "%s has disappeared", 305 sdlim->dxname); 306 destroy_sdlim(sdlim); 307 sdlim = next; 308 } 309 continue; 310 } 311 if (sdlim != NULL && 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); 317 TAILQ_REMOVE(&sdlims, sdlim, entries); 318 syslog(LOG_INFO, "%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) 327 TAILQ_INSERT_BEFORE(sdlim, next, entries); 328 else 329 TAILQ_INSERT_TAIL(&sdlims, next, entries); 330 syslog(LOG_INFO, "%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)) 337 return; 338 /* Ensure that our queue is consistent. */ 339 for (sdlim = TAILQ_FIRST(&sdlims); 340 (next = TAILQ_NEXT(sdlim, entries)) != NULL; 341 sdlim = next) 342 if (sdlim->dev > next->dev) 343 syslog(LOG_ALERT, "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_HW; 355 mib[1] = HW_SENSORS; 356 mib[2] = sdlim->dev; 357 len = sizeof(sensor); 358 359 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 360 if ((limit->flags & SENSORSD_L_ISTATUS) && 361 !(limit->flags & SENSORSD_L_USERLIMIT)) 362 continue; 363 364 mib[3] = limit->type; 365 mib[4] = limit->numt; 366 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1) 367 err(1, "sysctl"); 368 369 if (!(limit->flags & SENSORSD_L_ISTATUS)) { 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_USERLIMIT) { 386 enum sensorsd_s_status newustatus; 387 388 if (sensor.flags & SENSOR_FINVALID) 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}; 416 417 switch (fork()) { 418 case -1: 419 syslog(LOG_CRIT, "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) 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) { 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; 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_INFO : 470 LOG_ALERT, "%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[BUFSIZ]; 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_INFO : 506 LOG_ALERT, "%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[BUFSIZ]; 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_CRIT, "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, "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[RFBUFCNT][RFBUFSIZ]; /* ring buffer */ 636 static int idx; 637 char *fbuf; 638 639 fbuf = rfbuf[idx++]; 640 if (idx == RFBUFCNT) 641 idx = 0; 642 643 switch (type) { 644 case SENSOR_TEMP: 645 snprintf(fbuf, RFBUFSIZ, "%.2f degC", 646 (value - 273150000) / 1000000.0); 647 break; 648 case SENSOR_FANRPM: 649 snprintf(fbuf, RFBUFSIZ, "%lld RPM", value); 650 break; 651 case SENSOR_VOLTS_DC: 652 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0); 653 break; 654 case SENSOR_VOLTS_AC: 655 snprintf(fbuf, RFBUFSIZ, "%.2f V AC", value / 1000000.0); 656 break; 657 case SENSOR_WATTS: 658 snprintf(fbuf, RFBUFSIZ, "%.2f W", value / 1000000.0); 659 break; 660 case SENSOR_AMPS: 661 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0); 662 break; 663 case SENSOR_WATTHOUR: 664 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0); 665 break; 666 case SENSOR_AMPHOUR: 667 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0); 668 break; 669 case SENSOR_INDICATOR: 670 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off"); 671 break; 672 case SENSOR_INTEGER: 673 snprintf(fbuf, RFBUFSIZ, "%lld", value); 674 break; 675 case SENSOR_PERCENT: 676 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 677 break; 678 case SENSOR_LUX: 679 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0); 680 break; 681 case SENSOR_DRIVE: 682 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0])) 683 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]); 684 else 685 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 686 break; 687 case SENSOR_TIMEDELTA: 688 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0); 689 break; 690 case SENSOR_HUMIDITY: 691 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 692 break; 693 case SENSOR_FREQ: 694 snprintf(fbuf, RFBUFSIZ, "%.2f Hz", value / 1000000.0); 695 break; 696 case SENSOR_ANGLE: 697 snprintf(fbuf, RFBUFSIZ, "%lld", value); 698 break; 699 case SENSOR_DISTANCE: 700 snprintf(fbuf, RFBUFSIZ, "%.3f m", value / 1000000.0); 701 break; 702 case SENSOR_PRESSURE: 703 snprintf(fbuf, RFBUFSIZ, "%.2f Pa", value / 1000.0); 704 break; 705 case SENSOR_ACCEL: 706 snprintf(fbuf, RFBUFSIZ, "%2.4f m/s^2", value / 1000000.0); 707 break; 708 case SENSOR_VELOCITY: 709 snprintf(fbuf, RFBUFSIZ, "%4.3f m/s", value / 1000000.0); 710 break; 711 default: 712 snprintf(fbuf, RFBUFSIZ, "%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) 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, *ebuf = NULL; 732 char node[48]; 733 char *cfa[2]; 734 735 cfa[0] = cf; 736 cfa[1] = NULL; 737 738 TAILQ_FOREACH(p, &sdlim->limits, entries) { 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_ISTATUS; 747 if (cgetstr(buf, "low", &ebuf) < 0) 748 ebuf = NULL; 749 p->lower = get_val(ebuf, 0, p->type); 750 if (cgetstr(buf, "high", &ebuf) < 0) 751 ebuf = NULL; 752 p->upper = get_val(ebuf, 1, p->type); 753 if (cgetstr(buf, "command", &ebuf) < 0) 754 ebuf = NULL; 755 if (ebuf != NULL) { 756 p->command = ebuf; 757 ebuf = NULL; 758 } 759 free(buf); 760 buf = NULL; 761 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX) 762 p->flags |= SENSORSD_L_USERLIMIT; 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) { 774 if (upper) 775 return (LLONG_MAX); 776 else 777 return (LLONG_MIN); 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 } 849