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