1 /* $OpenBSD: sensorsd.c,v 1.66 2019/06/28 13:32:50 deraadt 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; 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 = optarg; 129 if (access(configfile, R_OK) != 0) 130 err(1, "access configuration file %s", 131 configfile); 132 break; 133 default: 134 usage(); 135 } 136 } 137 138 argc -= optind; 139 argv += optind; 140 if (argc > 0) 141 usage(); 142 143 if (configfile == NULL) 144 if (asprintf(&configfile, "/etc/sensorsd.conf") == -1) 145 err(1, "out of memory"); 146 147 if (unveil(configfile, "r") == -1) 148 err(1, "unveil"); 149 if (unveil("/", "x") == -1) 150 err(1, "unveil"); 151 152 if (pledge("stdio rpath proc exec", NULL) == -1) 153 err(1, "pledge"); 154 155 openlog("sensorsd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 156 157 create(); 158 159 parse_config(configfile); 160 161 if (debug == 0 && daemon(0, 0) == -1) 162 err(1, "unable to fork"); 163 164 signal(SIGHUP, reparse_cfg); 165 signal(SIGCHLD, SIG_IGN); 166 167 for (;;) { 168 if (reload) { 169 parse_config(configfile); 170 syslog(LOG_INFO, "configuration reloaded"); 171 reload = 0; 172 } 173 this_check = time(NULL); 174 if (!(last_report < this_check)) 175 this_check = last_report + 1; 176 check(this_check); 177 report(last_report); 178 last_report = this_check; 179 sleep(check_period); 180 } 181 } 182 183 void 184 create(void) 185 { 186 struct sensordev sensordev; 187 struct sdlim_t *sdlim; 188 size_t sdlen = sizeof(sensordev); 189 int mib[3], dev, sensor_cnt = 0; 190 191 mib[0] = CTL_HW; 192 mib[1] = HW_SENSORS; 193 194 for (dev = 0; ; dev++) { 195 mib[2] = dev; 196 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 197 if (errno == ENXIO) 198 continue; 199 if (errno == ENOENT) 200 break; 201 warn("sysctl"); 202 } 203 sdlim = create_sdlim(&sensordev); 204 TAILQ_INSERT_TAIL(&sdlims, sdlim, entries); 205 sensor_cnt += sdlim->sensor_cnt; 206 } 207 208 syslog(LOG_INFO, "startup, system has %d sensors", sensor_cnt); 209 } 210 211 struct sdlim_t * 212 create_sdlim(struct sensordev *snsrdev) 213 { 214 struct sensor sensor; 215 struct sdlim_t *sdlim; 216 struct limits_t *limit; 217 size_t slen = sizeof(sensor); 218 int mib[5], numt; 219 enum sensor_type type; 220 221 if ((sdlim = calloc(1, sizeof(struct sdlim_t))) == NULL) 222 err(1, "calloc"); 223 224 strlcpy(sdlim->dxname, snsrdev->xname, sizeof(sdlim->dxname)); 225 226 mib[0] = CTL_HW; 227 mib[1] = HW_SENSORS; 228 mib[2] = sdlim->dev = snsrdev->num; 229 230 TAILQ_INIT(&sdlim->limits); 231 232 for (type = 0; type < SENSOR_MAX_TYPES; type++) { 233 mib[3] = type; 234 for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) { 235 mib[4] = numt; 236 if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { 237 if (errno != ENOENT) 238 warn("sysctl"); 239 continue; 240 } 241 if ((limit = calloc(1, sizeof(struct limits_t))) == 242 NULL) 243 err(1, "calloc"); 244 limit->type = type; 245 limit->numt = numt; 246 TAILQ_INSERT_TAIL(&sdlim->limits, limit, entries); 247 sdlim->sensor_cnt++; 248 } 249 } 250 251 return (sdlim); 252 } 253 254 void 255 destroy_sdlim(struct sdlim_t *sdlim) 256 { 257 struct limits_t *limit; 258 259 while ((limit = TAILQ_FIRST(&sdlim->limits)) != NULL) { 260 TAILQ_REMOVE(&sdlim->limits, limit, entries); 261 free(limit->command); 262 free(limit); 263 } 264 free(sdlim); 265 } 266 267 void 268 check(time_t this_check) 269 { 270 struct sensordev sensordev; 271 struct sdlim_t *sdlim, *next; 272 int mib[3]; 273 int h, t, i; 274 size_t sdlen = sizeof(sensordev); 275 276 if (TAILQ_EMPTY(&sdlims)) { 277 h = 0; 278 t = -1; 279 } else { 280 h = TAILQ_FIRST(&sdlims)->dev; 281 t = TAILQ_LAST(&sdlims, sdlimhead_t)->dev; 282 } 283 sdlim = TAILQ_FIRST(&sdlims); 284 285 mib[0] = CTL_HW; 286 mib[1] = HW_SENSORS; 287 /* look ahead for 4 more sensordevs */ 288 for (i = h; i <= t + 4; i++) { 289 if (sdlim != NULL && i > sdlim->dev) 290 sdlim = TAILQ_NEXT(sdlim, entries); 291 if (sdlim == NULL && i <= t) 292 syslog(LOG_ALERT, "inconsistent sdlim logic"); 293 mib[2] = i; 294 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 295 if (errno != ENOENT) 296 warn("sysctl"); 297 if (sdlim != NULL && i == sdlim->dev) { 298 next = TAILQ_NEXT(sdlim, entries); 299 TAILQ_REMOVE(&sdlims, sdlim, entries); 300 syslog(LOG_INFO, "%s has disappeared", 301 sdlim->dxname); 302 destroy_sdlim(sdlim); 303 sdlim = next; 304 } 305 continue; 306 } 307 if (sdlim != NULL && i == sdlim->dev) { 308 if (strcmp(sdlim->dxname, sensordev.xname) == 0) { 309 check_sdlim(sdlim, this_check); 310 continue; 311 } else { 312 next = TAILQ_NEXT(sdlim, entries); 313 TAILQ_REMOVE(&sdlims, sdlim, entries); 314 syslog(LOG_INFO, "%s has been replaced", 315 sdlim->dxname); 316 destroy_sdlim(sdlim); 317 sdlim = next; 318 } 319 } 320 next = create_sdlim(&sensordev); 321 /* inserting next before sdlim */ 322 if (sdlim != NULL) 323 TAILQ_INSERT_BEFORE(sdlim, next, entries); 324 else 325 TAILQ_INSERT_TAIL(&sdlims, next, entries); 326 syslog(LOG_INFO, "%s has appeared", next->dxname); 327 sdlim = next; 328 parse_config_sdlim(sdlim, configfile); 329 check_sdlim(sdlim, this_check); 330 } 331 332 if (TAILQ_EMPTY(&sdlims)) 333 return; 334 /* Ensure that our queue is consistent. */ 335 for (sdlim = TAILQ_FIRST(&sdlims); 336 (next = TAILQ_NEXT(sdlim, entries)) != NULL; 337 sdlim = next) 338 if (sdlim->dev > next->dev) 339 syslog(LOG_ALERT, "inconsistent sdlims queue"); 340 } 341 342 void 343 check_sdlim(struct sdlim_t *sdlim, time_t this_check) 344 { 345 struct sensor sensor; 346 struct limits_t *limit; 347 size_t len; 348 int mib[5]; 349 350 mib[0] = CTL_HW; 351 mib[1] = HW_SENSORS; 352 mib[2] = sdlim->dev; 353 len = sizeof(sensor); 354 355 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 356 if ((limit->flags & SENSORSD_L_ISTATUS) && 357 !(limit->flags & SENSORSD_L_USERLIMIT)) 358 continue; 359 360 mib[3] = limit->type; 361 mib[4] = limit->numt; 362 if (sysctl(mib, 5, &sensor, &len, NULL, 0) == -1) 363 err(1, "sysctl"); 364 365 if (!(limit->flags & SENSORSD_L_ISTATUS)) { 366 enum sensor_status newastatus = sensor.status; 367 368 if (limit->astatus != newastatus) { 369 if (limit->astatus2 != newastatus) { 370 limit->astatus2 = newastatus; 371 limit->acount = 0; 372 } else if (++limit->acount >= 3) { 373 limit->last_val = sensor.value; 374 limit->astatus2 = 375 limit->astatus = newastatus; 376 limit->astatus_changed = this_check; 377 } 378 } 379 } 380 381 if (limit->flags & SENSORSD_L_USERLIMIT) { 382 enum sensorsd_s_status newustatus; 383 384 if (sensor.flags & SENSOR_FINVALID) 385 newustatus = SENSORSD_S_INVALID; 386 else if (sensor.value > limit->upper) 387 newustatus = SENSORSD_S_ABOVE; 388 else if (sensor.value < limit->lower) 389 newustatus = SENSORSD_S_BELOW; 390 else 391 newustatus = SENSORSD_S_WITHIN; 392 393 if (limit->ustatus != newustatus) { 394 if (limit->ustatus2 != newustatus) { 395 limit->ustatus2 = newustatus; 396 limit->ucount = 0; 397 } else if (++limit->ucount >= 3) { 398 limit->last_val = sensor.value; 399 limit->ustatus2 = 400 limit->ustatus = newustatus; 401 limit->ustatus_changed = this_check; 402 } 403 } 404 } 405 } 406 } 407 408 void 409 execute(char *command) 410 { 411 char *argp[] = {"sh", "-c", command, NULL}; 412 413 switch (fork()) { 414 case -1: 415 syslog(LOG_CRIT, "execute: fork() failed"); 416 break; 417 case 0: 418 execv("/bin/sh", argp); 419 _exit(1); 420 /* NOTREACHED */ 421 default: 422 break; 423 } 424 } 425 426 void 427 report(time_t last_report) 428 { 429 struct sdlim_t *sdlim; 430 431 TAILQ_FOREACH(sdlim, &sdlims, entries) 432 report_sdlim(sdlim, last_report); 433 } 434 435 void 436 report_sdlim(struct sdlim_t *sdlim, time_t last_report) 437 { 438 struct limits_t *limit; 439 440 TAILQ_FOREACH(limit, &sdlim->limits, entries) { 441 if ((limit->astatus_changed <= last_report) && 442 (limit->ustatus_changed <= last_report)) 443 continue; 444 445 if (limit->astatus_changed > last_report) { 446 const char *as = NULL; 447 448 switch (limit->astatus) { 449 case SENSOR_S_UNSPEC: 450 as = ""; 451 break; 452 case SENSOR_S_OK: 453 as = ", OK"; 454 break; 455 case SENSOR_S_WARN: 456 as = ", WARN"; 457 break; 458 case SENSOR_S_CRIT: 459 as = ", CRITICAL"; 460 break; 461 case SENSOR_S_UNKNOWN: 462 as = ", UNKNOWN"; 463 break; 464 } 465 syslog(limit->astatus == SENSOR_S_OK ? LOG_INFO : 466 LOG_ALERT, "%s.%s%d: %s%s", 467 sdlim->dxname, sensor_type_s[limit->type], 468 limit->numt, 469 print_sensor(limit->type, limit->last_val), as); 470 } 471 472 if (limit->ustatus_changed > last_report) { 473 char us[BUFSIZ]; 474 475 switch (limit->ustatus) { 476 case SENSORSD_S_UNSPEC: 477 snprintf(us, sizeof(us), 478 "ustatus uninitialised"); 479 break; 480 case SENSORSD_S_INVALID: 481 snprintf(us, sizeof(us), "marked invalid"); 482 break; 483 case SENSORSD_S_WITHIN: 484 snprintf(us, sizeof(us), 485 "within limits: %s", 486 print_sensor(limit->type, limit->last_val)); 487 break; 488 case SENSORSD_S_ABOVE: 489 snprintf(us, sizeof(us), 490 "exceeds limits: %s is above %s", 491 print_sensor(limit->type, limit->last_val), 492 print_sensor(limit->type, limit->upper)); 493 break; 494 case SENSORSD_S_BELOW: 495 snprintf(us, sizeof(us), 496 "exceeds limits: %s is below %s", 497 print_sensor(limit->type, limit->last_val), 498 print_sensor(limit->type, limit->lower)); 499 break; 500 } 501 syslog(limit->ustatus == SENSORSD_S_WITHIN ? LOG_INFO : 502 LOG_ALERT, "%s.%s%d: %s", 503 sdlim->dxname, sensor_type_s[limit->type], 504 limit->numt, us); 505 } 506 507 if (limit->command) { 508 int i = 0, n = 0, r; 509 char *cmd = limit->command; 510 char buf[BUFSIZ]; 511 int len = sizeof(buf); 512 513 buf[0] = '\0'; 514 for (i = n = 0; n < len; ++i) { 515 if (cmd[i] == '\0') { 516 buf[n++] = '\0'; 517 break; 518 } 519 if (cmd[i] != '%') { 520 buf[n++] = limit->command[i]; 521 continue; 522 } 523 i++; 524 if (cmd[i] == '\0') { 525 buf[n++] = '\0'; 526 break; 527 } 528 529 switch (cmd[i]) { 530 case 'x': 531 r = snprintf(&buf[n], len - n, "%s", 532 sdlim->dxname); 533 break; 534 case 't': 535 r = snprintf(&buf[n], len - n, "%s", 536 sensor_type_s[limit->type]); 537 break; 538 case 'n': 539 r = snprintf(&buf[n], len - n, "%d", 540 limit->numt); 541 break; 542 case 'l': 543 { 544 char *s = ""; 545 switch (limit->ustatus) { 546 case SENSORSD_S_UNSPEC: 547 s = "uninitialised"; 548 break; 549 case SENSORSD_S_INVALID: 550 s = "invalid"; 551 break; 552 case SENSORSD_S_WITHIN: 553 s = "within"; 554 break; 555 case SENSORSD_S_ABOVE: 556 s = "above"; 557 break; 558 case SENSORSD_S_BELOW: 559 s = "below"; 560 break; 561 } 562 r = snprintf(&buf[n], len - n, "%s", 563 s); 564 break; 565 } 566 case 's': 567 { 568 char *s; 569 switch (limit->astatus) { 570 case SENSOR_S_UNSPEC: 571 s = "UNSPEC"; 572 break; 573 case SENSOR_S_OK: 574 s = "OK"; 575 break; 576 case SENSOR_S_WARN: 577 s = "WARNING"; 578 break; 579 case SENSOR_S_CRIT: 580 s = "CRITICAL"; 581 break; 582 default: 583 s = "UNKNOWN"; 584 } 585 r = snprintf(&buf[n], len - n, "%s", 586 s); 587 break; 588 } 589 case '2': 590 r = snprintf(&buf[n], len - n, "%s", 591 print_sensor(limit->type, 592 limit->last_val)); 593 break; 594 case '3': 595 r = snprintf(&buf[n], len - n, "%s", 596 print_sensor(limit->type, 597 limit->lower)); 598 break; 599 case '4': 600 r = snprintf(&buf[n], len - n, "%s", 601 print_sensor(limit->type, 602 limit->upper)); 603 break; 604 default: 605 r = snprintf(&buf[n], len - n, "%%%c", 606 cmd[i]); 607 break; 608 } 609 if (r == -1 || (r >= len - n)) { 610 syslog(LOG_CRIT, "could not parse " 611 "command"); 612 return; 613 } 614 if (r > 0) 615 n += r; 616 } 617 if (buf[0]) 618 execute(buf); 619 } 620 } 621 } 622 623 const char *drvstat[] = { 624 NULL, "empty", "ready", "powerup", "online", "idle", "active", 625 "rebuild", "powerdown", "fail", "pfail" 626 }; 627 628 static char * 629 print_sensor(enum sensor_type type, int64_t value) 630 { 631 static char rfbuf[RFBUFCNT][RFBUFSIZ]; /* ring buffer */ 632 static int idx; 633 char *fbuf; 634 635 fbuf = rfbuf[idx++]; 636 if (idx == RFBUFCNT) 637 idx = 0; 638 639 switch (type) { 640 case SENSOR_TEMP: 641 snprintf(fbuf, RFBUFSIZ, "%.2f degC", 642 (value - 273150000) / 1000000.0); 643 break; 644 case SENSOR_FANRPM: 645 snprintf(fbuf, RFBUFSIZ, "%lld RPM", value); 646 break; 647 case SENSOR_VOLTS_DC: 648 snprintf(fbuf, RFBUFSIZ, "%.2f V DC", value / 1000000.0); 649 break; 650 case SENSOR_VOLTS_AC: 651 snprintf(fbuf, RFBUFSIZ, "%.2f V AC", value / 1000000.0); 652 break; 653 case SENSOR_WATTS: 654 snprintf(fbuf, RFBUFSIZ, "%.2f W", value / 1000000.0); 655 break; 656 case SENSOR_AMPS: 657 snprintf(fbuf, RFBUFSIZ, "%.2f A", value / 1000000.0); 658 break; 659 case SENSOR_WATTHOUR: 660 snprintf(fbuf, RFBUFSIZ, "%.2f Wh", value / 1000000.0); 661 break; 662 case SENSOR_AMPHOUR: 663 snprintf(fbuf, RFBUFSIZ, "%.2f Ah", value / 1000000.0); 664 break; 665 case SENSOR_INDICATOR: 666 snprintf(fbuf, RFBUFSIZ, "%s", value? "On" : "Off"); 667 break; 668 case SENSOR_INTEGER: 669 snprintf(fbuf, RFBUFSIZ, "%lld", value); 670 break; 671 case SENSOR_PERCENT: 672 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 673 break; 674 case SENSOR_LUX: 675 snprintf(fbuf, RFBUFSIZ, "%.2f lx", value / 1000000.0); 676 break; 677 case SENSOR_DRIVE: 678 if (0 < value && value < sizeof(drvstat)/sizeof(drvstat[0])) 679 snprintf(fbuf, RFBUFSIZ, "%s", drvstat[value]); 680 else 681 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 682 break; 683 case SENSOR_TIMEDELTA: 684 snprintf(fbuf, RFBUFSIZ, "%.6f secs", value / 1000000000.0); 685 break; 686 case SENSOR_HUMIDITY: 687 snprintf(fbuf, RFBUFSIZ, "%.2f%%", value / 1000.0); 688 break; 689 case SENSOR_FREQ: 690 snprintf(fbuf, RFBUFSIZ, "%.2f Hz", value / 1000000.0); 691 break; 692 case SENSOR_ANGLE: 693 snprintf(fbuf, RFBUFSIZ, "%lld", value); 694 break; 695 case SENSOR_DISTANCE: 696 snprintf(fbuf, RFBUFSIZ, "%.3f m", value / 1000000.0); 697 break; 698 case SENSOR_PRESSURE: 699 snprintf(fbuf, RFBUFSIZ, "%.2f Pa", value / 1000.0); 700 break; 701 case SENSOR_ACCEL: 702 snprintf(fbuf, RFBUFSIZ, "%2.4f m/s^2", value / 1000000.0); 703 break; 704 case SENSOR_VELOCITY: 705 snprintf(fbuf, RFBUFSIZ, "%4.3f m/s", value / 1000000.0); 706 break; 707 default: 708 snprintf(fbuf, RFBUFSIZ, "%lld ???", value); 709 } 710 711 return (fbuf); 712 } 713 714 void 715 parse_config(char *cf) 716 { 717 struct sdlim_t *sdlim; 718 719 TAILQ_FOREACH(sdlim, &sdlims, entries) 720 parse_config_sdlim(sdlim, cf); 721 } 722 723 void 724 parse_config_sdlim(struct sdlim_t *sdlim, char *cf) 725 { 726 struct limits_t *p; 727 char *buf = NULL, *ebuf = NULL; 728 char node[48]; 729 char *cfa[2]; 730 731 cfa[0] = cf; 732 cfa[1] = NULL; 733 734 TAILQ_FOREACH(p, &sdlim->limits, entries) { 735 snprintf(node, sizeof(node), "hw.sensors.%s.%s%d", 736 sdlim->dxname, sensor_type_s[p->type], p->numt); 737 p->flags = 0; 738 if (cgetent(&buf, cfa, node) != 0) 739 if (cgetent(&buf, cfa, sensor_type_s[p->type]) != 0) 740 continue; 741 if (cgetcap(buf, "istatus", ':')) 742 p->flags |= SENSORSD_L_ISTATUS; 743 if (cgetstr(buf, "low", &ebuf) < 0) 744 ebuf = NULL; 745 p->lower = get_val(ebuf, 0, p->type); 746 if (cgetstr(buf, "high", &ebuf) < 0) 747 ebuf = NULL; 748 p->upper = get_val(ebuf, 1, p->type); 749 if (cgetstr(buf, "command", &ebuf) < 0) 750 ebuf = NULL; 751 if (ebuf != NULL) { 752 p->command = ebuf; 753 ebuf = NULL; 754 } 755 free(buf); 756 buf = NULL; 757 if (p->lower != LLONG_MIN || p->upper != LLONG_MAX) 758 p->flags |= SENSORSD_L_USERLIMIT; 759 } 760 } 761 762 int64_t 763 get_val(char *buf, int upper, enum sensor_type type) 764 { 765 double val; 766 int64_t rval = 0; 767 char *p; 768 769 if (buf == NULL) { 770 if (upper) 771 return (LLONG_MAX); 772 else 773 return (LLONG_MIN); 774 } 775 776 val = strtod(buf, &p); 777 if (buf == p) 778 err(1, "incorrect value: %s", buf); 779 780 switch (type) { 781 case SENSOR_TEMP: 782 switch (*p) { 783 case 'C': 784 printf("C"); 785 rval = val * 1000 * 1000 + 273150000; 786 break; 787 case 'F': 788 printf("F"); 789 rval = (val * 1000 * 1000 + 459670000) / 9 * 5; 790 break; 791 default: 792 errx(1, "unknown unit %s for temp sensor", p); 793 } 794 break; 795 case SENSOR_FANRPM: 796 rval = val; 797 break; 798 case SENSOR_VOLTS_DC: 799 case SENSOR_VOLTS_AC: 800 if (*p != 'V') 801 errx(1, "unknown unit %s for voltage sensor", p); 802 rval = val * 1000 * 1000; 803 break; 804 case SENSOR_PERCENT: 805 rval = val * 1000.0; 806 break; 807 case SENSOR_INDICATOR: 808 case SENSOR_INTEGER: 809 case SENSOR_DRIVE: 810 case SENSOR_ANGLE: 811 rval = val; 812 break; 813 case SENSOR_WATTS: 814 case SENSOR_AMPS: 815 case SENSOR_WATTHOUR: 816 case SENSOR_AMPHOUR: 817 case SENSOR_LUX: 818 case SENSOR_FREQ: 819 case SENSOR_ACCEL: 820 case SENSOR_DISTANCE: 821 case SENSOR_VELOCITY: 822 rval = val * 1000 * 1000; 823 break; 824 case SENSOR_TIMEDELTA: 825 rval = val * 1000 * 1000 * 1000; 826 break; 827 case SENSOR_HUMIDITY: 828 case SENSOR_PRESSURE: 829 rval = val * 1000.0; 830 break; 831 default: 832 errx(1, "unsupported sensor type"); 833 /* not reached */ 834 } 835 free(buf); 836 return (rval); 837 } 838 839 /* ARGSUSED */ 840 void 841 reparse_cfg(int signo) 842 { 843 reload = 1; 844 } 845