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