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