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