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