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